/* MULE.C
 * Main code for MULE
 *************
 * 29.08.2000 : Toni R„s„nen
 *              modifications/documentation for open source
 *       0.61 : Toni R„s„nen
 *              bugfixes, minor improvements
 *
 * TODO: SHOP AI IMPLEMENTATION
 */


/* prodsprites:
        0=house, 1..4=product type sprites;
        5..8=nominal prod sprites;
        9..16=actual prod sprites */

// debugcode
// check!
// todo:

#include <stdlib.h>
#include <stdio.h>
#include <pc.h>
#include <string.h>
#include "math.h"
#include "gfx2.h"
#include "mpack.h"
#include "timer.h"
#include "keys.h"
#include "mixer.h"
#include "mod.h"
#include "pakfile.h"
#include "mainmenu.h"
#include "version.h"
#include "sound.h"
#include "sndconf.h"
#include "loader.h"
#include "intro.h"
#include "auct.h"

#define A_SELL 2
#define A_BUY 0

#define R_FOOD 0
#define R_ENERGY 1
#define R_ORE 2
#define R_CRYSTAL 3

#define IDELAYTIME 1500

int idelaytime;

// a small pun. i let you figure out how to actually see it... :)
char allworketc[] = {"All work and no play makes Highway a dull boy"};

// nominal prices for shop goods
float nominalprice[4] = { 20,30,80, 110 };

//production: 1=food, 2=ener, 3=ore, 4=cryst
int muletraincost[5] = { 0, 50, 85, 75, 100 };

// races: 1:human 2:compalien, 3:chicken, 4:? 5:gray 6:pacman 7:worms 8:lightning
// max time: 2500    - max money: 1600
int race_startmoney[9] = { 0000, 800, 1200, 1600, 1200, 1200, 1200, 1200, 1200 };
int race_turntime[9] = { 0000, 1600, 2000, 2800, 2000, 2000, 2000, 2000, 2000 };

typedef struct {  int plrgoods[5]; //5=shop, 0..3=plr
                  int plrusage[5];
                  int spoilmin; // minimum level to rest to spoil
                  float spoillevel; // amount which spoils, percents
                  int plrprod[5];
                  int plrneed[5];
                  int storeamount;
                  int storebuyprice;
                  int storesellprice;
               }  auction_struct;
               
// other vars for saving: game_length
static int savegame_beg;
// savegames
static int month;
static char planetmap[3][9*9]; // layers; 0=land, 1=mounts etc [city on layer 0]
static char planetres[4][9*9]; // resources
static char mapowner[9*9],  // owners 1..4, or 0 for none
            mapprod[9*9];   // production id at square (0=none)
  // next: map containing what sqr has produced
static char prodmap[9*9],  // prodmap : original prodmap (is cleared in process)
            prodmap2[9*9], // prodmap2: already drawn prod
            prodmap3[9*9]; // prodmap3: actual prod
static char mapknownprod[4][9*9]; // known prod for each resource
static char mapknowncrist[9*9]; // -1=not checked; 0..4; crist level
static char mapclaimscore[9*9]; // comp eval; square claim scoring
static char maxclaimscore; // max claim score value
static char mapprodscale[4][9*9]; // turn's map production scale, base = 10h = 100%

static int shop_ore,shop_oreprice;
static int shop_energy,shop_energyprice;
static int shop_food,shop_foodprice;
static int shop_crystalprice,shop_crist;
static int shop_mules;
static char nobartime[5]; // 0..3, human players only

static int plr_money[5];
static int plr_food[5],plr_foodneed[5]; // both plr0-based
static int plr_ore[5]; // plr0-based
static int plr_energy[5], plr_energyneed[5]; // both plr0-based
static int plr_crystal[5]; // plr0-based
static int shop_goodslevel[5];

static int plr_foodprod[4]; // plr0-based
static int plr_energyprod[4]; // plr0-based
static int plr_oreprod[4]; // plr0-based
static int plr_crystalprod[4]; // plr0-based
static int comp_reaction[4]; // comp reaction time; 0..20 (0=ultrafast, 20=barely can react)
static int comp_strategy[4]; // comp strategy; 0=for ore, 1=for cristite
static float comp_pricelevel[4]; // comp pricelevel to buy; 0=max, 1=min
static int landauct_startprice;
static int nopiratetime; // time since last pirate ship
static int nooreeatertime; // time since last ore eater invasion
static int mapxmax,mapymax,mapxmin,mapymin;
static float priceangle;
// savegames end
static int savegame_end; // array for safety

auction_struct aucts;

char *mapbackg;

char mapmodfd[9*9];
char colortable[10];
unsigned char colortableouter[10] = { 0, 0x30, 0x40, 0x20, 0xb0, 0x80, 0x90, 0, 0, 0 };
unsigned char colortable2[10];
int mapsprc;
int afterturnevent;

int leader,scores[4],posit[4],goodsscore[4],landscore[4];
int bushx[20],bushy[20],bushpic[20],bushtype[20],bushupdate;

char ackd[6],ackdi[6];

int muleprice = 100;
char *shopmulepic; // sprite

int muletaken;
int mulefitted;
int mulerunaway;

int changed;

char auctmessage[50];
volatile static int auctmessagetime;

char citymsg[50];
int citymsgtime;

char *buyline;
char *sellline;
char *stockbar;
char *stockpic1,*stockpic2;
char *shoppic;

//--------------------------------------------------------------------

/* ------------------------------------------------------ */

void check_mapbug()
{  int i;
   for (i = 0; i < 81; i++)
     if ( (mapowner[i] > 5) || (mapowner[i] < 0) )
       i = 82;
}

void setpalcol (int c, int r, int g, int b)
{  gen_palette[c*3+0] = r;
   gen_palette[c*3+1] = g;
   gen_palette[c*3+2] = b;
}

void set_gridpal (int clr)
{  int i;
   float r, g, b,s;
   switch (clr)
     {  case 0 : r=64; g=64; b=64; break; // white
        case 1 : r=64; g= 0; b= 0; break; // red
        case 2 : r= 0; g=64; b= 0; break; // green
        case 3 : r=45; g=47; b=64; break; // metal
        case 4 : r=64; g=64; b= 0; break; // yellow
        case 5 : r= 0; g=64; b=64; break; // cyan
        case 6 : r=64; g= 0; b=64; break; // purple
     }

   s = 0.14;
   for (i = 0; i < 16; i++)
     {  setpalcol (239-i, (int)(r*s), (int)(g*s), (int)(b*s) );
        s += (0.37-0.14) / 16.0;
     }
   setpale (64,64,64);
}


void play_errorsound()
{
//   int i;
//   for (i = 1000; i > 100; i -= 5)
//     {  sound(i); sound (1100-i); }
//   nosound();
}

void play_acksound()
{  /*int i;
   for (i = 1000; i > 100; i -= 5)
     sound(i);
   nosound(); */
}


void delaytimer()
{  if (delaytime) delaytime--;
}

//------------------
void delay(int time)
{  void *storerout;

   storerout = timer_routine;

   delaytime = time;
   timer_routine = delaytimer;

   while (delaytime && !exitgame)
     {  check_shutdown();
     }

   timer_routine = storerout;
}


// wait for all playrs to ack
// 0 in case of timeout
int delayi (int time)
{  void *storerout;
   int i,c;

   storerout = timer_routine;
   if (time < 10000)
     for (i=0; i < 4; i++) ackdi[i] = !plrcontrol[i];
   else
     time -= 10000;

   check_mapbug();

   delaytime = time;
   timer_routine = delaytimer;

   while (delaytime && !exitgame)
     {  readjoy();
        for (i = 0; i < 4; i++)
           {  if ((plrcontrol[i]) && (getk (i,K_FIRE)) && (!ackdi[i]) )
                {  ackdi[i] = 1; play_acksound();
                   setk (i,K_FIRE,0);
                }
           }
        for (c=0,i=0; i < 4; i++)
          if (ackdi[i]) c++;
        if (c == 4)
          {  timer_routine = storerout;
             return 1;
          }

        check_shutdown();
        if (exitgame) break;

        if (keybuffer[1] && keybuffer[88])
          {  keybuffer[88] = 0; break; }
     }

   timer_routine = storerout;
   return 0;
}

// return 0 in case of timeout, 1 in case of ack
int delayp (int plr,int time)
{  void *storerout;

   if (!plrcontrol[plr]) return 1; // computer; no acks

   storerout = timer_routine;

   delaytime = time;
   timer_routine = delaytimer;

   while (delaytime && !exitgame)
     {  readjoy();
        if (getk(plr,K_FIRE))
          {  timer_routine = storerout;
             setk (plr,K_FIRE,0);
             return 1;
          }
        check_shutdown();
        if (exitgame) break;
     }

   timer_routine = storerout;
   return 0;
}

// waits for any player to acknowledge
// return 0 in case of timeout, 1 in case of ack
int delayap (int time)
{  void *storerout;
   int i;

   check_mapbug();
   storerout = timer_routine;

   delaytime = time;
   timer_routine = delaytimer;

   while (delaytime && !exitgame)
     {  readjoy();
        for (i = 0; i < 4; i++)
          if ((plrcontrol[i]) && (getk(i,K_FIRE)) )
            {  timer_routine = storerout;
               setk (i,K_FIRE,0);
               return 1;
            }
        check_shutdown();
        if (exitgame) break;
     }

   timer_routine = storerout;
   return 0;
}

void play_tradesound()
{  //sound (500); delay (1); nosound();
}

//-------------------------------------------------------------
void putpiccolorize (int x, int y, char *kuva, unsigned char color)
{
  int xsize,ysize,yco,xco,xadd;
  int xmaxadd;
  int offs,n;
  unsigned char b;
  xsize = *((int*) (kuva+0) );
  ysize = *((int*) (kuva+4) );

  if (x <= -xsize) return;
//     (x+xsize <= 0)

  n = 8;
  xmaxadd = 0;

  if (y < 0)
    {  if ( (y+ysize) < 0) return;
       n -= y*xsize;
       ysize += y;
       y = 0;
    }

  if (x < 0)
    {  n -= x;
       xmaxadd = -x;
       xsize += x;
       x = 0;
    }

  if (y+ysize >= yclipmax)
    {  ysize = yclipmax-y;  }

  offs = y*sxsize+x;

  if (x+xsize >= xclipmax)
    { xmaxadd = (x+xsize)-xclipmax; xsize = xclipmax-x; }
  xadd = sxsize-xsize;

  for (yco=0; yco<ysize; yco++)
    {  for (xco=0; xco<xsize; xco++)
         {  if ( (b = *(kuva+n++)) )
              {  if ( (b & 0xe0) == 0xe0)
                   *(spritedest+offs) = (unsigned char) ((b & 0x0f) + color);
                 else
                   *(spritedest+offs) = b;
              }
            offs++;
         }
       offs += xadd;
       n += xmaxadd;
    }
}

void putanimpic (int x, int y, char *kuva)
{
  int xsize,ysize,yco,xco,xadd;
  int xmaxadd;
  register int offs,n;
  unsigned char b;
  int xclip,yclip;
  
  xsize = *((int*) (kuva+0) );
  ysize = *((int*) (kuva+4) );

  x -= mapsize->cminx;
  y -= mapsize->cminy;

  xclip = (mapsize->cmaxx - mapsize->cminx) + 1;
  yclip = (mapsize->cmaxy - mapsize->cminy) + 1;

  if (x <= -xsize) return;

  n = 8;
  xmaxadd = 0;

  if (y < 0)
    {  if ( (y+ysize) < 0) return;
       n -= y*xsize;
       ysize += y;
       y = 0;
    }

  if (x < 0)
    {  n -= x;
       xmaxadd = -x;
       xsize += x;
       x = 0;
    }

  if (y+ysize >= yclip )
    {  ysize = yclip-y;  }

  offs = (y+mapsize->cminy)*sxsize+(x+mapsize->cminx);

  if (x+xsize >= xclip)
    { xmaxadd = (x+xsize)-xclip; xsize = xclip-x; }
  xadd = sxsize-xsize;

//  offs += mapsize->minx+320*mapsize->miny;

  for (yco=0; yco<ysize; yco++)
    {  for (xco=0; xco<xsize; xco++)
         {  if ( (b = *(kuva+n++)) )
              *(spritedest+offs) = b;
            offs++;
         }
       offs += xadd;
       n += xmaxadd;
    }
}



void iswap (int *a, int *b)
{  int c;
   c = *a; *a = *b; *b = c;
}

void bbar (int x1,int y1, int x2,int y2)
{  if (x1 > x2) iswap (&x1, &x2);
   if (y1 > y2) iswap (&y1, &y2);
   movememo (x1,y1, x2-x1+1, y2-y1+1, backg, spritedest);
}


void vcline (int x1,int x2, int y, int s1,int s2)
{  int d;
   s1 <<= 8; s2 <<= 8;
   d = (s2-s1) / (x2-x1+1);
   while (x1 < x2)
     {  putp (x1,y, s1>>8 );
        s1 += d;
        x1++;
     }

   flip();
}

void hcline (int y1,int y2, int x, int s1,int s2)
{  int d;
   s1 <<= 8; s2 <<= 8;
   d = (s2-s1) / (y2-y1+1);
   while (y1 < y2)
     {  putp (x,y1, s1>>8 );
        s1 += d;
        y1++;
     }

   flip();
}

void msgwindow(char *r1, char *r2, char *r3)
{  int l,l1,l2,l3,x1,y1, x2,y2, ly1,ly2;

   l1 = getflen (r1,1) / 2;
   l2 = getflen (r2,1) / 2;
   l3 = getflen (r3,1) / 2;

   if (!strlen(r2))
     { y1 = 90; y2 = 110; ly1 = 96; }
   else
     if (!strlen(r3))
       { y1 = 85; y2 = 115; ly1 = 90; ly2 = 100; }

   if (l1 > l2) l = l1; else l = l2;
   if (l3 > l) l = l3;

   x1 = 160-l-10;
   x2 = 160+l+10;

   drawcolor = 0;
   abar (x1,y1,x2,y2);

   vcline ( x1,x2, y1, 176,185);
   hcline ( y1,y2, x1, 176,185);

   vcline ( x1,x2, y2, 185,176);
   hcline ( y1,y2, x2, 185,176);

   writef (160-l1,ly1, r1, 1);
   if (strlen(r2)) writef (160-l2,ly2, r2, 1);

   flip();
}


/*
// *******************************************************************
void luerivi (int x, int y, char *erivi, int maxlen, int pixlen)
{  unsigned char rivi[45],c;
   int i;

   if ((maxlen & 0x100) == 0)
     strcpy (erivi, "");

   maxlen &= 0xff;
   pixlen &= (~3);

   while (1)
     {
        movememo (x,y, pixlen,10, backg,ruutu);
        strcpy (rivi,erivi);
        strcat (rivi,"*");
        writef (x,y, rivi, 1);
        flip();

        c = getkh();

        i = strlen(erivi);

        if ((c > 31) && (c < 157) && (i < maxlen))
          {
//             if (c != '.')
               {  rivi[0] = c; rivi[1] = 0;
                  strcat (erivi,rivi);
               }
          }

        if (c == 8)
          {
             if (i > 0)
               erivi[i-1] = 0;
          }

        if (c == 13)
          break;
     }
}
*/

#define map0(a,b) planetmap[0][b*9+a]
#define map1(a,b) planetmap[1][b*9+a]

// analyze map and set its mineral(etc) content
void set_mineralcontent()
{  int o,am,b;
   memset (planetres, 0, 81*4); // clear all, nothing anywhere

   // find food distribution
   for (o=0; o < 9*9; o++)
     {  am = 0;
        b = planetmap[1][o];
        if ( (b >= 13) && (b <= 25) ) // river, 35+d10
          am += 35+(rand() % 10);
        else
          {  if (planetmap[0][o] == 39) // dirt, 15+d10
               am += 15+(rand() % 10);
             if (planetmap[0][o] == 40) // grassy, 25+d10
               am += 25+(rand() % 10);
          }
            
        if ( (b >= 1) && (b <= 3) ) // mount; -size*7
          am -= b * 7;

        if (am < 0) am = 0;
        if (am > 40) am = 40;
        planetres[R_FOOD][o] = am;
     }

   // find ore distribution
   for (o=0; o < 9*9; o++)
     {  am = 0;
        b = planetmap[1][o];
        if ( (b >= 1) && (b <= 3) )
          am += b*(12+(rand() % 3));
        am += (rand() % 5)+5;

        if (am < 0) am = 0;
        if (am > 40) am = 40;
        planetres[R_ORE][o] = am;
     }

   // find energy distribution
   for (o=0; o < 9*9; o++)
     {  am = 0;
        b = planetmap[1][o];
        am = 35+(rand() % 10);
        if ( (b >= 1) && (b <= 3) )
          am -= b * 12;

        if (am < 0) am = 0;
        if (am > 40) am = 40;
        planetres[R_ENERGY][o] = am;
     }
}

// 1:small, 2:med, 3:large
void add_1mount (int x, int y, int sqr)
{  if (x == 4 && y == 4) return; // city, no way
   if (x < 0 || x > 8) return; // outside
   if (y < 0 || y > 8) return; // outside
   if ( (map1(x,y) >= 13) && (map1(x,y) <= 38) ) return; // river, can't add mnt

   map1(x,y) += sqr;
   if (map1(x,y) > 3) map1(x,y) = 3;
}

// size; 1..3; size of mount
void add_mount_tomap (int size)
{  int x,y, xd,yd;
   x = rand() % 9;
   y = rand() % 9;

   switch (size)
     {  case 1 : // hills
                 add_1mount (x+0,y+0, 1);
                 add_1mount (x+(rand() % 2),y, 1);
                 add_1mount (x-(rand() % 2),y, 1);
                 add_1mount (x,y-(rand() % 2), 1);
                 add_1mount (x,y+(rand() % 2), 1);
                 break;
        case 2 : // med mnt
                 add_1mount (x+0,y+0, 2);
                 xd = (rand() % 3) -1; yd = (rand() % 3) -1;
                 add_1mount (x+xd,y+yd, 2);
                 add_1mount (x+1,y+0, 1);
                 add_1mount (x-1,y+0, 1);
                 add_1mount (x,y+1, 1);
                 add_1mount (x,y-1, 1);
                 break;
        case 3 : add_1mount (x,y, 3);
                 xd = (rand() % 3) -1; yd = (rand() % 3) -1;
                 add_1mount (x+xd,y+yd, 2);
                 xd = (rand() % 3) -1; yd = (rand() % 3) -1;
                 add_1mount (x+xd,y+yd, 2);
                 add_1mount (x+1,y, 1);
                 add_1mount (x-1,y, 1);
                 add_1mount (x,y+1, 1);
                 add_1mount (x,y-1, 1);
                 add_1mount (x-1,y-1, 1);
                 add_1mount (x+1,y-1, 1);
                 add_1mount (x+1,y+1, 1);
                 add_1mount (x-1,y+1, 1);
                 break;
     }
}

/* crist field:   1 1 1
                1 1 2 1 1
                1 2 3 2 1
                1 1 2 1 1
                  1 1 1 */
char cristfield[5][5] = { { 0,1,1,1,0 },
                          { 1,1,2,1,1 },
                          { 1,2,3,2,1 },
                          { 1,1,2,1,1 },
                          { 0,1,1,1,0 } };

void add_1crist (int x, int y, int sqr)
{  if (x == 4 && y == 4) return; // city, no way hos‚
   if (x < 0 || x > 8) return; // outside
   if (y < 0 || y > 8) return; // outside

   planetres[R_CRYSTAL][x+y*9] += (sqr*10);
   if (planetres[R_CRYSTAL][x+y*9] > 40)
     planetres[R_CRYSTAL][x+y*9] = 40;
}

                          
void add_cristitefield()
{  int x,y,xd,yd;
   x = (rand() % 9) - 2;
   y = (rand() % 9) - 2;

   for (xd = 0; xd < 5; xd++)
     for (yd = 0; yd < 5; yd++)
       add_1crist (x+xd,y+yd,cristfield[yd][xd]);
}

// create world map
void create_map()
{  int i,c,b;
   // clear
   memset (planetmap[0], 39, 81); map0(4,4) = 0; // terrain layer, city
   memset (planetmap[1], 0, 81); // mnt/river layer
   memset (mapknownprod, 0, 81*4); // known prods
   memset (mapknowncrist,-1, 81); // known kristite layer; not known
   memset (mapowner, 0, 81); mapowner[4*9+4] = 5; // owner layer, city = none

   // add some grass
   for (i = 0; i < 20; i++)
     map0(rand()%9,rand()%9) = 40;
   // add river to the map
   map1(4,0) = 13;
   map1(4,1) = 16;
   map1(4,2) = 15;
   map1(4,3) = 13;

   map1(4,5) = 13;
   map1(4,6) = 15;
   map1(4,7) = 13;
   map1(4,8) = 14;


   map0(4,4) = 0; // terrain layer, city

   for (i = 0; i < 6; i++)
     add_mount_tomap ( (rand() % 3) + 1);

   set_mineralcontent();

   for (i = 0; i < 4; i++) // add 3 cristite fields
     add_cristitefield();

   for (i = 0; i < 20; i++)
     {  do {  bushx[i] = mapsize->minx + (rand() % (mapsize->maxx - mapsize->minx - 10) );
              bushy[i] = mapsize->miny + (rand() % (mapsize->maxy - mapsize->miny - 10) );
              bushtype[i] = ANM_BUSH1 + (rand() % 2);
              bushpic[i] = 1;

              c = 0;
/*              if ( (bushx[i] > (12+4*22-5) ) && (bushx[i] < (12+5*22+5) ) &&
                   (bushy[i] > (1+4*22-5) ) && (bushy[i] < (1+5*22+5) ) ) c++; */
              b = map1( ((bushx[i]-12)/22),((bushy[i]-1)/22) );
              if ( (b >= 13) && (b <= 38) ) c++; // river
           }  while (c);
     }
}

void draw_map()
{  int o,x,y,b,i;
//   char rivi[5];

   if (mapsize->allowtable[0] == 0) // not full-sized map; get map background
     {  movememo (12,1, 9*22,9*22, mapbackg, ruutu);
     }

   spritedest = ruutu;

   // show lower and higher layer of map
   for (o=0,y=0; y < 9; y++)
     {  for (x = 0; x < 9; x++,o++)
          {  if (mapsize->allowtable[o])
               putnpic ( 12+x*22, 1+y*22, mapsprites[(int)planetmap[0][o]]);
          }
     }
   for (o=0,y=0; y < 9; y++)
     {  for (x = 0; x < 9; x++,o++)
          {  if ( (mapsize->allowtable[o]) && (b=planetmap[1][o]) )
               putnpic ( 12+x*22, 1+y*22, mapsprites[b]);
          }
     }

   // decor: bushes
   for (i = 0; i < 20; i++)
     putnpic (bushx[i],bushy[i],animspr[bushtype[i]][bushpic[i]]);


   // map ownership (selection) sprites
   for (o=0,y=0; y < 9; y++)
     {  for (x = 0; x < 9; x++,o++)
          {  if ( (mapsize->allowtable[o]) && (b=mapowner[o]) && (!ackd[b]) )
               {  putnpic ( 12+x*22, 1+y*22, selsprites[(int)colortable[b]]);
               }
          }
     }

/*
   for (o=0,y=0; y < 9; y++)
     {  for (x = 0; x < 9; x++,o++)
          {  if ( (b=mapowner[o]) && (!ackd[b]) && (b < 5) )
               {  prod = mapprod[o];
                  putpiccolorize ( 12+x*22, 1+y*22, prodsprites[prod], colortable2[b]);
                  if (mapprod[o])
                    {  pc = (mapknownprod[prod-1][o]+2) / 10; // 0..40
                       if (pc > 4) pc = 4;
                       if (pc > 0)
                         putpiccolorize ( 12+x*22, 1+y*22, prodsprites[4+pc], colortable2[mapowner[o]]);
                    }
               }
          }
     } */
}

// show what is being produced at square, and
// also known production
void draw_mapprod()
{  int o,x,y,b,prod,pc;

   for (o=0,y=0; y < 9; y++)
     {  for (x = 0; x < 9; x++,o++)
          {  if ( (mapsize->allowtable[o]) && (b=mapowner[o]) && (!ackd[b]) && (b < 5) )
               {  prod = mapprod[o];
                  putpiccolorize ( 12+x*22, 1+y*22, prodsprites[prod], colortable2[b]);
                  if (mapprod[o])
                    {  pc = (mapknownprod[prod-1][o]+2) / 10; // 0..40
                       if (pc > 4) pc = 4;
                       if (pc > 0)
                         putpiccolorize ( 12+x*22, 1+y*22, prodsprites[(int)(4+pc)], colortable2[(int)(mapowner[o])]);
                    }
               }
          }
     }
}

void remove_playermap(int i)
{  int o,x,y,b;
   for (o=0,y=0; y < 9; y++)
     {  for (x = 0; x < 9; x++,o++)
          {  if (mapowner[o] == (i+1) )
               putnpic ( 12+x*22, 1+y*22, mapsprites[(int)(planetmap[0][o]) ]);
          }
     }
   for (o=0,y=0; y < 9; y++)
     {  for (x = 0; x < 9; x++,o++)
          {  if ( (b=planetmap[1][o]) && (mapowner[o] == (i+1) ) )
               putnpic ( 12+x*22, 1+y*22, mapsprites[b]);
          }
     }

}

int get_next_mappiece(int o)
{
   do { o++;
      } while ( (o < 82) && (!mapsize->allowtable[o]) );
   return o;
}

int get_next_free_mappiece(int o)
{  o = get_next_mappiece(o);

   while (o < 82)
     {  if (mapowner[o] == 0) break;
        o = get_next_mappiece(o);
     }
   return (o);

}

int get_some_free_mappiece()
{  int c,o;
   o = rand() % 82;
   c = 0;
   while (c < 82)
     {  if (!mapsize->allowtable[o])
          o++;
        else
          if (mapowner[o] == 0) break;
        o++;
        if (o >= 81) o = 0;
        c++;
     }
   if (c == 82) return -1;
   return (o);

}

void reset_acks()
{  int i;
   ackd[5] = 1;
   for (i=0; i < 4; i++)
     ackd[i] = !plrcontrol[i];
}

void zero_acks()
{  int i;
   ackd[5] = 0;
   for (i = 0; i < 4; i++)
     ackd[i] = 0;
}

int get_acks()
{  int i,c;
   for (c=0,i=0; i < 4; i++)
     if (ackd[i]) c++;
   return (c);
}


void claim_mappiece (int o, int plr)
{  mapowner[o] = plr+1;
   mapprod[o] = 0;
/*   mapknownprod[R_FOOD][o] = 0; // known productions for resources
   mapknownprod[R_ORE][o] = 0;
   mapknownprod[R_ENERGY][o] = 0;
   mapknownprod[R_CRYSTAL][o] = 0; */
}

void remove_evalsquares(int firstavail)
{  int o;

   maxclaimscore = 0;
   for (o = 0; o < 81; o++)
     {  if (o < firstavail) mapclaimscore[o] = 0;
        if (mapowner[o]) mapclaimscore[o] = 0;

        if (mapclaimscore[o] > maxclaimscore) maxclaimscore = mapclaimscore[o];
     }
}

void comp_evaluate_squares()
{  // cristite scores high (10+)
   // mounts next (3..5)
   // river scores next (3)
   // flat land next (1+random 1..6)
   int o,b;

   maxclaimscore = 0;
   for (o = 0; o < 81; o++)
     {
        mapclaimscore[o] = 0;
        if (mapknowncrist[o] != -1) // if crist is known
          mapclaimscore[o] += 10+(mapknowncrist[o]*3); // high crist, high score
          
        if ( (b=planetmap[1][o] > 0) && (planetmap[1][o] < 4) )
          mapclaimscore[o] += 2+(b*2); // mount scoring; 3..5

        if ( (b > 13) && (b <= 38) )
          mapclaimscore[o] += 3; // river; equals to hills

         // add according to player needs?

        mapclaimscore[o] += (1+(rand() % 6));

        if (mapowner[o]) mapclaimscore[o] = 0;

        if (mapsize->allowtable[o] == 0) mapclaimscore[o] = 0; // can't be taken


     }

   // basic evaluation done...
}

void reset_keys()
{  int i;
   for (i = 0; i < 4; i++)
     setk (i,K_FIRE,0);
}


//???????????????????????????????????????????????????????????????????
void land_grand()
{  int o,i,x,y,ctrl,landgranded;
   char claimed[4];

   for (i = 0; i < 4; i++) claimed[i] = 0;

   if (exitgame) return;

   landgrand_accelerate = 0;
   purakuva ("mapgrid.dat", ruutu);
   memmove (mapbackg,ruutu,64000);
   set_gridpal (0);
   draw_map();
   draw_mapprod();
   timer_routine = landgrand_timerrout;

   memmove (backg, ruutu, 64000);

   writef (215,20, "LAND GRANT", 1);

   comp_evaluate_squares();

   o = get_next_free_mappiece(-1);

   zero_acks();
   draw_map();
   draw_mapprod();

   landgranded = 0;

   if (o >= 81)
     {  writef (215,40, "No free land", 1);
        writef (215,48, "to be claimed.", 1);

        flip();

        delayi (idelaytime);

        return;
     }
   
   writef (215,40, "Press your button", 1);
   writef (215,48, "to claim piece of", 1);
   writef (215,56, "land", 1);

   memmove (ruutu2, ruutu, 64000);

   flip();
   delay (50);

   landgrand_count = 500;

   // heh heh... no holding fire down :)
   reset_keys();
   while (1 && !exitgame)
     {  if (landgrand_count > 8)
          {  if (landgrand_count < 500)
               o = get_next_free_mappiece(o);
             remove_evalsquares(o);
             maxclaimscore -= 2;

             if (o == 81)
               break;

             draw_map();
             draw_mapprod();
             x = o % 9; y = o / 9;
             putnpic ( 12+x*22, 1+y*22, selsprites[0]);
             landgrand_count = 0;
             if (landgranded)
               {  landgrand_count -= 16; landgranded = 0; }

/*             for (o2=0,y=0; y < 9; y++)
               {  for (x = 0; x < 9; x++,o2++)
                    {  sprintf (rivi, "%i", mapclaimscore[o2]);
                       writef (12+x*22, 1+y*22, rivi, 1);
                    }
               } */ // debugcode
             
             flip();
          }

        readjoy();
        for (i = 0; i < 4; i++)
          {  if ( (ctrl=plrcontrol[i]) == 0) // computer
               { // AI SCRIPT
                  if ((!claimed[i]) && ( (mapclaimscore[o]-(rand() % 3)) >= maxclaimscore ) && (mapowner[o]== 0) )
                    {  if (landgrand_count > comp_reaction[i])
                          {  claimed[i] = 1;
                             claim_mappiece (o, i);
                             landgranded++;
                             landgrand_count = 500;
                          }
                    }

               }
             else
               {  if (getk(i,K_FIRE))
                    if ( (!claimed[i]) && (mapowner[o] == 0) )
                      {  claimed[i] = 1;
                         claim_mappiece (o, i);
                         setk (i,K_FIRE,0);
                         landgranded++;
                         landgrand_count = 500;
                      }
               }
          } // for

        for (ctrl=0,i=0; i < 4; i++)
          if (claimed[i]) ctrl++;
        if (ctrl == 4) break;

        check_shutdown();
        if (exitgame) return;

     } // while 1

   drawcolor = 0; bbar (215,40, 319,90);

   writef (215,40, "Land claimed", 1);

   landgrand_count = 0;
   draw_map();
   draw_mapprod();
   flip();

   reset_acks();
   while (get_acks() < 4 && !exitgame)
     {  readjoy();
        for (i = 0; i < 4; i++)
           {  if ((plrcontrol[i]) && (getk(i,K_FIRE)) && (!ackd[i]))
                {  ackd[i] = 1;
                   play_acksound();
                   changed++;
                   remove_playermap(i);
                }
          }
        if (changed) {  flip(); changed = 0; }

        check_shutdown();
        if (exitgame) return;
     }

   reset_keys();

   timer_routine = NULL;

}


//---------------------------------------------------------------
// evaluates land pieces according to their production
void evaluate_lands()
{  int o,prod;
   for (o = 0; o < 81; o++)
     if ( (mapowner[o] >= 1) && (mapowner[o] <= 4) )
       {  prod = mapprod[o]-1; // prod# 1..4
          mapknownprod[prod][o] = planetres[prod][o];
       }
}

//---------------------------------------------------------------

int getox(int o)
{  return (o % 9);  }
int getoy(int o)
{  return (o / 9);  }

int get_lineneighs(int o, int own)
{  int x,y,i, bon;
   x = o % 9;
   y = o / 9;

   bon = -70;
                                                          //
   for (i = x; i > 0; --i)                                //     x
     if (mapowner[y*9+i] == own) bon += 25; else break;   //  xxxx
   for (i = x; i < 9; ++i)                                //
     if (mapowner[y*9+i] == own) bon += 25; else break;   //
                                                          //
   for (i = y; i > 0; --i)                                //
     if (mapowner[i*9+x] == own) bon += 25; else break;
   for (i = y; i < 9; ++i)
     if (mapowner[i*9+x] == own) bon += 25; else break;

   return bon;
}

int get_neighbors(int o, int prod, int owner)
{  int cx,cy, x,y, bon;
   cx = getox(o); cy = getoy(o);

   bon = 0;
   for (x=cx-1; x <=cx+1; x++)
     for (y=cy-1; y <=cy+1; y++)
       if ( (x >= 0) && (x <= 8) && (y >= 0) && (y <= 8) )
         if ( (x != cx) || (y != cy) )
           {  // if neighbor square has same production
              if (mapprod[x+y*9]-1 == prod)
                {  if (mapowner[x+y*9] == owner)
                     bon += 30; // same owner
                   else
                     bon += 15; // different owner
                }
           }
   return bon;
}

// scores for planting a production
int get_neighbors2(int o, int prod, int owner)
{  int cx,cy, x,y, bon;
   cx = getox(o); cy = getoy(o);

   bon = 0;
   for (x=cx-1; x <=cx+1; x++)
     for (y=cy-1; y <=cy+1; y++)
       if ( (x >= 0) && (x <= 8) && (y >= 0) && (y <= 8) )
         if ( (x != cx) || (y != cy) )
           {  // if neighbor square has same production
              if (mapprod[x+y*9]-1 == prod)
                {  if (mapowner[x+y*9] == owner)
                     bon += 2; // same owner
                   else
                     bon += 1; // different owner
                }
           }
   return bon;
}

int get_neighborcount(int o, int owner)
{  int cx,cy, x,y, bon;
   cx = getox(o); cy = getoy(o);

   bon = 0;
   for (x=cx-1; x <=cx+1; x++)
     for (y=cy-1; y <=cy+1; y++)
       if ( (x >= 0) && (x <= 8) && (y >= 0) && (y <= 8) )
         if ( (x != cx) || (y != cy) )
           {  // if neighbor square has same production
              if (mapowner[x+y*9] == owner)
                bon ++; // same owner
           }
   return bon;
}


// main production
void create_prodmap()
{  int o,am,prod,scale,maxprod,finscale,bonus,own;

   check_mapbug();

   memset (prodmap, 0, 81);

   for (o=0; o<81; o++)
     if (( (own=mapowner[o]) > 0) && (mapowner[o] < 5) && (mapprod[o]) )
       {  prod = mapprod[o]-1; // prod# 1..4
          scale = mapprodscale[prod][o]; // 10h = 100%

          // if not enough energy to produce...
          // shortage: eff = 25% + [% of energy available]
          // energy shortage doesn't affect solar collectors
          if ( (plr_energy[own] < plr_energyneed[own]) && (prod != R_ENERGY) )
            scale = ((scale*4) + (scale*plr_energy[own]*12 / plr_energyneed[own]) ) / 16;

            // maxprod; scale *
          maxprod = scale * planetres[prod][o] / 16;

          // maxprod=40

          // bonus production; neighboring squares
          if (plrrace[own-1] == 7) // worms
            bonus = get_lineneighs(o, own); // worms; lines give bonus
          else
            bonus = get_neighbors(o, prod, own); // others; grouping gives bonus


          if (plrrace[own-1] == 8) // electricitymen? get major bonus for electricity, penalty for others
            {  if (prod == R_ENERGY)
                 bonus += 180; // some two units more
               else
                 bonus -= 80; // one less
            }
            
          finscale = 8 + ((rand() % 5) + (rand() % 6)) / 2;

          // finscale=10

          // calc final production amount
          am = (maxprod * finscale + 40 + bonus) / 100;

          // 400 + 40 + bonus = 440, /100 = 4

          if (am > 8)
            am = 8; // limit to 8 (no problems)

          switch (prod)
            {  case R_ORE     : plr_oreprod[own-1] += am; break;
               case R_FOOD    : plr_foodprod[own-1] += am; break;
               case R_ENERGY  : plr_energyprod[own-1] += am; break;
               case R_CRYSTAL : plr_crystalprod[own-1] += am; break;
            }

          prodmap[o] = am;
          prodmap3[o] = am;

          check_mapbug();
       }

}


// get single random prod point where IS something produced
int get_prodpos (int *xp, int *yp, int *op )
{  int o;

   check_mapbug();
   while (1 && !exitgame)
     {  do { o = rand() % 81;
           } while (mapsize->allowtable[o] == 0);
           
        if ( prodmap[o] )
          {  *xp = 12+getox(o)*22;
             *yp =  1+getoy(o)*22;
             *op = o;

             check_mapbug();
             return (prodmap2[o]+1);
          }


        if ((keybuffer[1]) && (keybuffer[88])) break;
     }
   return 0;
}

//---------------------------------------------------------------
/* display productions slowly */
void show_prodmap()
{  int added_plot, co,o, x,y,c,i,r, mapsqs, lgtim,lc;

    // get prod total; for every prod
   for (co=0,o=0; o < 81; o++)
     co += prodmap[o];
     
    // clear "drawn" prodmap
   memset (prodmap2, 0, 81);

   timer_routine = landgrand_timerrout;

   // prodsprites 9+n
   counter = 10;
   flip();

    // find count of used squares (for sound timing)
   for (mapsqs=i=0; i < 81; i++)
     if (mapowner[i]) mapsqs++;
   mapsqs /= 15;

   lc = 2;
   lgtim = 1;
   added_plot = 0;
   
   while (co && !exitgame)
     {  check_mapbug();

         // sound; if time changed
        if (landgrand_count != lgtim)
          {  landgrand_count = lgtim;
             lc--;
             if (lc <= 0)
               {
                  if (added_plot) // if added a prod picture
                    {  playsound (SND_PRODUCT,26050);
                       added_plot = 0;
                    }
                  lc = 7+(rand() % 12);
               }
          }
     
        if (!counter)
          {  changed++; counter = 10-mapsqs;
              // get random prod position, making sure that there
              // IS production
             do {  c = get_prodpos ( &x, &y, &o );
                   r = 0;
                   if ( (o < 0) || (o > 80) )
                     r++;
                } while (r);
             
             check_mapbug();

              // increase drawn; decrease available
             prodmap2[o]++;
             prodmap[o]--;

              // show actual production
             putpiccolorize (x,y, prodsprites[(int)(8+c)], colortable2[(int)mapowner[o]]);
             added_plot ++;
             co--;
             check_mapbug();
          }

        if (changed)
          flip();

        check_mapbug();

        // in case of a bug: ESC-F12 terminates loop  
        if ((keybuffer[1]) && (keybuffer[88])) break;
     }

   reset_acks();
   while (get_acks() < 4 && !exitgame)
     {  readjoy();
        for (i = 0; i < 4; i++)
           {  if ((plrcontrol[i]) && (getk (i,K_FIRE)) && (!ackd[i]))
                {  ackd[i] = 1;
                   play_acksound();
                   changed++;
                   remove_playermap(i);
                }
          }
        if (changed) {  flip(); changed = 0; }

        check_shutdown();
        if (exitgame) return;
     }

   reset_keys();

   timer_routine = NULL;
}

//---------------------------------------------------------------
// draw all prods QUICKLY (prodsprites 9..16 = actual production)
void show_prodmapfast()
{  int o;

   for (o = 0; o < 81; o++)
     {  if ( (mapprod[o]) && (prodmap3[o]) )
          putpiccolorize (12+(o % 9)*22,1+(o / 9)*22, prodsprites[(int)(8+prodmap3[o])], colortable2[(int)(mapowner[o])]);
     }

}

//---------------------------------------------------------------

void show_productions()
{  int o,x,y,prod,pc,i;
   int lgtim,lc;

   if (exitgame) return;

   purakuva ("mapgrid.dat", ruutu); setpale (64,64,64);
   memmove (mapbackg,ruutu,64000);
   set_gridpal (0);
   check_mapbug();

   zero_acks();
   draw_map();
   draw_mapprod();
   check_mapbug();

   evaluate_lands();
   check_mapbug();

   lgtim = -1;
   spritedest = ruutu; lc = 2+(rand() % 5);
   for (o=0,y=0; y < 9; y++)
     {  for (x = 0; x < 9; x++,o++)
          {  if ( (mapowner[o] > 0) && (mapowner[o] < 5) && (!ackd[(int)mapowner[o]] ) )
               {  prod = mapprod[o];
                   // current production
                  putpiccolorize ( 12+x*22, 1+y*22, prodsprites[prod], colortable2[(int)mapowner[o]]);
                  pc = (mapknownprod[prod-1][o]+2) / 10; // 0..40
                  if (mapprod[o])
                    {  if (pc > 4) pc = 4;
                       if (pc > 0)
                         putpiccolorize ( 12+x*22, 1+y*22, prodsprites[4+pc], colortable2[(int)mapowner[o]]);
                    }
                  check_mapbug();
               }
          }
     }

   check_mapbug();

   for (i = 0; i < 4; i++)
     { plr_foodprod[i] = 0;
       plr_energyprod[i] = 0;
       plr_oreprod[i] = 0;
       plr_crystalprod[i] = 0;
     }
   create_prodmap();

   writef (220,20,"Month's",1);
   writef (220,30,"production",1);

   show_prodmap();
}

//---------------------------------------------------------------

void sabar (int x1,int y1, int x2, int y2)
{  if (y1 < 68) y1 = 68;
   if (y2 < 68) y2 = 68;
   if (y1 > 162) y1 = 162;
   if (y2 > 162) y2 = 162;
   while (y1 <= y2)
     {  putnpic (x1,y1, stockbar);
        y1 ++;
     }
}

int ytoprice(int y)
{  // 56..147
   float diff;

   diff = aucts.storesellprice-aucts.storebuyprice;
   return (int) ( ( ((float)(-y+163))/96.0 )*diff + aucts.storebuyprice );
}

int pricetoy(int p)
{  // 56..147
   float a,storediff;
   int y;

   a = p - aucts.storebuyprice;
   storediff = aucts.storesellprice-aucts.storebuyprice;

   y = 163-(int) ( (163.0-67.0)* (a/storediff) );

   if (y > 169)
     return 169;
   else
     return y;

}

//-------------------------------------
int get_step (volatile int* step)
{ // 0 :  0..4
  // 4 :  5..9
  // 8 : 10..14
  // 4 : 15..19
  if (*step < 0) *step = 0;
  if (*step > 19) *step = 0;

  if (*step < 5) return 0;
  if (*step < 10) return 4;
  if (*step < 15) return 8;
  return 4;
  
}

//-------------------------------------
int get_step2 (volatile int* step)
{ // 0 :  0..2
  // 4 :  3..5
  // 8 :  6..8
  // 4 :  9..11
  if (*step < 0) *step = 0;
  if (*step > 11) *step = 0;

  if (*step < 3) return 0;
  if (*step < 6) return 4;
  if (*step < 9) return 8;
  return 4;
  
}


void playwithdelay (int snd, int freq, int delayt)
{  if (!snd_device) return;

   playsound (snd, freq);
   delay (delayt);
}

// ***************************************************************
void land_auction()
{  int i,x,y,ly,z,ii;
   int ypos[4],price[4],
       notmoved,highestbuy,lowestsell,shopbuys,landsquare;
   int advance,retreat;

   int comp_wantland[4];
   int comp_maxoffer[4];
   int step[5];
   float r;

   if (exitgame) return;
   
   timer_routine = landgrand_timerrout;

   landsquare = get_some_free_mappiece();

   if (landsquare == -1) return; // no land left.

   purakuva ("mapgrid.dat", ruutu); setpale (64,64,64);
   memmove (mapbackg,ruutu,64000);
   set_gridpal (0);
   zero_acks();
   draw_map();
   draw_mapprod();
   writef (220,10,"LAND FOR SALE",1);
   flip();

   delayi (1);
   for (i = 0; i < 200; i++)
     {  draw_map();
        draw_mapprod();
        if (i & 1)
          putnpic ( 12+(landsquare % 9)*22, 1+(landsquare / 9)*22, selsprites[0]);
        flip();
        if (delayi (10010)) break;
     }

   purakuva ("auct.dat", ruutu2);
   purakuva ("lauctb.dat", backg);
   spritedest = ruutu2;
   getpic (86,117,99,117,stockbar);
   getpic (71,101,231,103,sellline);
   getpic (71,105,231,107,buyline);
   getpic (49,1,75,18,shoppic);
   getpic (1, 97,1+22, 97+22, stockpic1);
   getpic (25,97,25+22,97+22, stockpic2);
   spritedest = ruutu;

   memmove (ruutu, backg, 64000);
   setpale (64,64,64);

        //***************************
   drawcolor = 0;
   bbar (0,0,319,50);

   aucts.storebuyprice = landauct_startprice;
   aucts.storesellprice = aucts.storebuyprice+140;

   for (i = 0; i < 4; i++) step[i] = 8;

   // COMP AI / land purchase....................
   for (i=0; i < 4; i++)
     if (plrcontrol[i] == 0)
       {  ii = plr_money[i];
          ii -= (rand() % 1000);
          ii -= (300); // always leaver at least 300cr
          if (ii > 2000) ii /= 2;
          if (ii > 2000) ii /= 2;
          if (ii > 1000) ii = ii * 2 / 3;
          ii = ii - 100 + (rand() % 300); // at least one mule
          while (ii > plr_money[i])
            ii -= 300;
          comp_maxoffer[i] = ii;

          if (comp_maxoffer[i] >= aucts.storebuyprice)
            comp_wantland[i] = 1;
          else
            comp_wantland[i] = 0;
       }
   
   writemid (160,10,"LAND AUCTION");
   sprintf (rivi,"BIDS START FROM $%i", aucts.storebuyprice);
   writemid (160,178,rivi);

   putnpic (30-11,5,stockpic1);
   putnpic (290-11,5,stockpic2);

   for (i = 0; i < 4; i++)
     {  price[i] = aucts.storebuyprice - 5;
        ypos[i] = pricetoy(price[i]);
        putpiccolorize (85+i*45,ypos[i]-24,racesprites[(int)plrrace[i]][4+0],colortable2[i+1] );
     }

   ly = 68;
   drawcolor = 0xb6; aline (300,68,300,162);
   drawcolor = 0xb2; aline (301,68,301,162);
   drawcolor = 0xb4; aline (302,68,302,162);
   drawcolor = 0xb7; aline (303,68,303,162);
   drawcolor = 0xba; aline (304,68,304,162);

   landgrand_count = 0;
   landgrand_accelerate = 0;
   changed = 3;

   highestbuy = -1;
   lowestsell = -1;

   shopbuys = 1;
   sellcounter = -1;

   auctmessagetime = 0;

   flip();
   delay (50);
   
   while (1 && !exitgame)
     {  y = 68+(landgrand_count / (1000/95) );
        if (y != ly)
          {  drawcolor = 0; bbar (300,ly,305,y); ly = y;
             changed |= 1;
          }

        if (landgrand_count < 1000)
          {  timetick_speed = 150- (145 * landgrand_count / 1000);
          }

        if (landgrand_count > 1000)
          {  for (z=0,i=0; i < 4; i++)
               if (price[i] < aucts.storebuyprice) z++;
             if (z==4)
               {  writemid (160,100,"NO ONE BUYS THE LAND");
                  r = 80+(rand() % 20);
                  r /= 100;
                  landauct_startprice = (int)(((float)(landauct_startprice)) * r);
               }
             else
               {  for (z=0,i=0; i < 4; i++)
                    if ( price[i] > z ) {  z = price[i]; y = i;  }

                  // plr "y" buys
                  sprintf (rivi,"LAND SOLD FOR $%i", z);
                  writemid (160,100,rivi);

                  claim_mappiece(landsquare,y);
                  plr_money[y] -= z;
                  landauct_startprice = z;
                    
               }
             flip();
             playwithdelay (SND_BELL,22050,20);
             playwithdelay (SND_BELL,22050,20);
             playwithdelay (SND_BELL,22050,20);
             delayi (idelaytime);
             break;
          }

        if (!counter)
          { counter = 2;
            readjoy();
            // player controls
            notmoved = 1;
            for (i = 0; i < 4; i++)
              {  advance = 0;
                 retreat = 0;
                 
                 if (!plrcontrol[i]) // computer
                   {
                     if (comp_wantland[i])
                        {  if (price[i] < aucts.storebuyprice) advance++;
                           if (price[i] < comp_maxoffer[i]) // comp can offer more ...
                             {  // check if others leading or nearby
                                z = x = y = 0; // x=lead, y=near back
                                for (ii = 0; ii < 4; ii++)
                                  if (ii != i)
                                    {  if ( (price[ii] < price[i]) && (price[i]-price[ii] < 10) ) y++;
                                       if ( (price[ii] < price[i]) && (price[i]-price[ii] == 10) ) z++;
                                       if (price[ii] >= price[i]) x++;
                                    }
                                if (y || x) advance++;
                                if (!x && !y && !z) retreat++;
                             }
                           else
                             {  x = z = 0;
                                for (ii=0; ii < 4; ii++)
                                  {  if ( (price[ii] < price[i]) && (price[i]-price[ii] > 10) ) z++;
                                     if ( price[ii] > price[i]) x++;
                                  }
                                if (z && !x) retreat++;
                             }
                        }
                   }
                 else
                   {  if (getk(i,K_UP)) advance = 1;
                      if (getk(i,K_DOWN)) retreat = 1;

                   } // if !plrcontrol else

                 if (advance)
                   {  if (price[i] < plr_money[i]) // must have CASH!
                        {  if ( (price[i] >= aucts.storesellprice) )
                             {  price[i] += 4;
                                aucts.storesellprice = price[i];
                                aucts.storebuyprice = aucts.storesellprice-100;
                                notmoved = 0;
                                if (price[i] > plr_money[i])
                                  price[i] = plr_money[i];
                                landgrand_count--;
                                for (ii=0;ii<4;ii++)
                                  ypos[ii] = pricetoy(price[ii]);
                                changed |= 2;
                             }
                           else
                             price[i] += 4;
                        }
                      ypos[i] = pricetoy(price[i]);
                      changed |= 2;
                      if ( (price[i] >= aucts.storebuyprice) &&
                           (price[i] <= aucts.storesellprice) ) notmoved=0;
                    } // if advance

                 if (retreat)
                   {  if (price[i] > ytoprice(168)) price[i] -= 2;
                      ypos[i] = pricetoy(price[i]);
                      changed |= 2;
                      if ( (price[i] >= aucts.storebuyprice) &&
                           (price[i] <= aucts.storesellprice) ) notmoved=0;
                   } // if retreat

                 if (advance || retreat)
                   step[i]++;
                   
              } // for i
            landgrand_accelerate = notmoved; // if no-one moves, accelerate time
            // buy/sell

            for (z=0,i=0; i < 4; i++)
              {  if ( (highestbuy == -1) && (price[i] >= aucts.storebuyprice) ) highestbuy = i;
                 if ( (highestbuy != -1) && (price[i] > price[highestbuy]) ) highestbuy = i;
                 if (price[i] < aucts.storebuyprice) z++;
              }
            if (z==4) highestbuy = -1;


          } // if !counter

        if ( (auctmessagetime == 0) && (auctmessage[0] != 0) )
          {  auctmessage[0] = 0;
             changed |= 2;
          }

        if (changed)
          {  if (changed & 2)
               {  movememo(66,20, 210,150, backg, ruutu);
                  movememo(66,190, 190,9, backg, ruutu);

                  for (z=-1,i=0; i < 4; i++)
                    if ( price[i] > z ) z = price[i];
                  if (z >= aucts.storebuyprice)
                    {  itoa (z,rivi,10);
                       putnpic (80,pricetoy(z)-1,buyline); // shop
                       writemid (255, pricetoy(z)-4, rivi);
                    }

                  writef (30,30,"CREDITS:",1);
                  for (i = 0; i < 4; i++)
                    {  if (plrrace[i] == 8)
                         putpiccolorize (85+i*45,ypos[i]-23,racesprites[(int)plrrace[i]][(rand() %3)*4+0],colortable2[i+1] );
                       else
                         putpiccolorize (85+i*45,ypos[i]-23,racesprites[(int)plrrace[i]][get_step2(&step[i])+0],colortable2[i+1] );

                       itoa (plr_money[i],rivi,10);
                       writemid (97+i*45,30, rivi);
                    }
                  changed |= 1;
               }
             if (changed & 1) flip();
             changed = 0;
          }
        if (keybuffer[1]) break;

        check_shutdown();
     }
   landgrand_accelerate = 0;

   timer_routine = NULL;
}

// old auct
void computer_analyze_crystal_sell (int plr, float *price, int *amount, int buyprice )
{  float nominal;

   *amount = aucts.plrgoods[plr];

   nominal = nominalprice[R_CRYSTAL];
   nominal -= (nopiratetime*4);
   if (nominal < 10) nominal = 10;

   *price = buyprice / nominal;
}

// old auct
void computer_analyze_food_sell (int plr, float *price, int *amount, int buyprice )
{  float nominal;

   *amount = aucts.plrgoods[plr]-plr_foodneed[plr];

   nominal = nominalprice[R_FOOD];

   *price = buyprice / nominal;
}


// old auct
void computer_analyze_energy_sell (int plr, float *price, int *amount, int buyprice )
{  float nominal;

   *amount = aucts.plrgoods[plr]-plr_energyneed[plr];

   nominal = nominalprice[R_ENERGY];

   *price = buyprice / nominal;
}

// for old auct
void computer_analyze_ore_sell (int plr, float *price, int *amount, int buyprice )
{  float nominal;

   *amount = aucts.plrgoods[plr];

   nominal = nominalprice[R_ORE];
   nominal -= (nooreeatertime*2);
   if (nominal < 10) nominal = 10;

   *price = buyprice / nominal;
}



int y_to_price (int y, auctiontype *auct, char *rivi)
{  int price;
   float f;

   f = ( ((float)(163-y)) / 97.0 );

   price = (auct->shopbuyprice) + f * ( (auct->shopsellprice)-(auct->shopbuyprice)+1);

   sprintf (rivi, "%i", price);
   return price;
}

float price_to_y (int price, auctiontype *auct)
{
   float spbp1;
   float bp,sp;

   bp = auct->shopbuyprice;
   sp = auct->shopsellprice;

   spbp1 = (sp-bp+1);

   return ( 163 + (bp*97)/spbp1 - (price*97)/spbp1 );
}


int auctpicy[5] = { 97, 49, 25, 1, 73 }; // pic ypos
char auctnames[5][15] = { "Land","Food","Energy","Ore","Cristite" };

void show_new_auction ( auctiontype *auct )
{  int i, x,y,z, changed,count;
   int step[5];
   int ly, traded[4], selling,buying;
   float pricespeed,f;
   int buy_y,sell_y,price,accel;

   char tradewith[4]; // -1=na, 0..3=plr, 4=shop
   int tradespeed[4]; // current exchange speed

   if (exitgame) return;

   timer_routine = landgrand_timerrout;

   if (auct->aucttype) // 0=land; otherwise goods
     purakuva ("auctb.dat", backg);
   else
     purakuva ("lauctb.dat", backg);

   purakuva ("auct.dat", ruutu2);

   y = auctpicy[auct->aucttype];
   spritedest = ruutu2;
   getpic (86,117,99,117,stockbar);
   getpic (71,101,231,103,sellline);
   getpic (71,105,231,107,buyline);
   getpic (1, y,1+22, y+22, stockpic1);
   getpic (25,y,25+22,y+22, stockpic2);
   getpic (49,1,75,18,shoppic);

   memmove (ruutu, backg, 64000);
   
   setpale (64,64,64);

   if (auct->aucttype) // NOT LAND AUCTION -- goods amount changes
     {
        spritedest = ruutu;
        writemid (160,10,"STOCK CHANGES DURING THE MONTH");

        sprintf (rivi, "%s in stock", auctnames[auct->aucttype]);
        writemid (160,30,rivi);
     
        putnpic (30-11,5,stockpic1);
        putnpic (290-11,5,stockpic2);
     
        drawcolor = 8; aline (70,148,250,148);
     
        // BEGINNING STOCK--------------------------------------->
     
        for (i = 0; i < 4; i++)
          {  putpiccolorize (100+i*40-11,150,racesprites[(int)plrrace[i]][4+2],colortable2[i+1] );
             itoa (auct->amount[i], rivi, 10);
             writemid (100+i*40,175, rivi);
             drawcolor = 7;
             y = 147-(auct->amount[i]*2); if (y < 57) y = 57;
             sabar (100+i*40-7,y ,100+i*40+7,147);
          }
     
        flip();
        delayap (idelaytime);
     
        for (i = 0; i < 4; i++) step[i] = 8;
     
        // USAGE------------------------------------------------->
        movememo (20,30,280,10, backg,ruutu);
        sprintf (rivi, "%s usage", auctnames[auct->aucttype]);
        writemid (160,30,rivi);
     
        count = 0;
        for (i = 0; i < 4; i++)
          if (auct->consumption[i] > count) count = auct->consumption[i];
     
        flip();
        landgrand_count = 0;
        while (count > 0 && !exitgame)
          {  if (landgrand_count > 1)
               {  for (i = 0; i < 4; i++)
                    if (auct->consumption[i])
                      {  if (auct->amount[i]) auct->amount[i]--;
                         auct->consumption[i]--;
                         x = 100+i*40;
                         y = 145-(auct->amount[i]*2);
                         if (y > 56)
                           bbar (x-7,y,x+7,y+1);
     
                         bbar (x-15,175,x+15,185);
                         itoa (auct->amount[i], rivi, 10);
                         writemid (x,175, rivi);
                      }
                  landgrand_count = 0;
                  count--;
                  flip();
                  
               }
             check_shutdown();
             if (exitgame) return;
          }
     
        delayap (idelaytime);
     
        // SPOILAGE ------------------------------------------->
        movememo (20,30,280,10, backg,ruutu);
        sprintf (rivi, "%s spoiled", auctnames[auct->aucttype]);
        writemid (160,30,rivi);
     
        count = 0;
        for (i = 0; i < 4; i++)
          if (auct->spoilage[i] > count) count = auct->spoilage[i];
     
        flip();
        landgrand_count = 0;
        while (count > 0 && !exitgame)
          {  if (landgrand_count > 1)
               {  for (i = 0; i < 4; i++)
                    if (auct->spoilage[i])
                      {  if (auct->amount[i]) auct->amount[i]--;
                         auct->spoilage[i]--;
                         x = 100+i*40;
                         y = 145-(auct->amount[i]*2);
                         if (y > 56)
                           bbar (x-7,y,x+7,y+1);
     
                         bbar (x-15,175,x+15,185);
                         itoa (auct->amount[i], rivi, 10);
                         writemid (x,175, rivi);
                      }
                  landgrand_count = 0;
                  count--;
                  flip();
                  
               }
             check_shutdown();
             if (exitgame) return;
          }
     
        delayap (idelaytime);

        // PRODUCTION---------------------------------------------->

        movememo (20,30,280,10, backg,ruutu);
        sprintf (rivi, "%s produced", auctnames[auct->aucttype]);
        writemid (160,30,rivi);
     
        count = 0;
        for (i = 0; i < 4; i++)
          if (auct->production[i] > count) count = auct->production[i];
     
        flip();
        landgrand_count = 0;
        while (count > 0 && !exitgame)
          {  if (landgrand_count > 1)
               {  for (i = 0; i < 4; i++)
                    if (auct->production[i])
                       {  auct->amount[i]++;
                          auct->production[i]--;
                          x = 100+i*40;
                          y = 147-(auct->amount[i]*2);
                          drawcolor = 7;
                          if (y > 56)
                            sabar (x-7,y,x+7,y+1);
     
                          drawcolor = 0;
                          bbar (x-15,175,x+15,185);
                          itoa (auct->amount[i], rivi, 10);
                          writemid (x,175, rivi);
                       }
                  landgrand_count = 0;
                  count--;
                  flip();
               }
             check_shutdown();
             if (exitgame) return;
          }
     
        delayap (idelaytime);
     
        //---final stock
        movememo (20,30,280,10, backg,ruutu);
        sprintf (rivi, "%s level", auctnames[auct->aucttype]);
        writemid (160,30,rivi);
     
        sprintf (rivi,"Store has %i units", auct->shopamount);
        writemid (160,187,rivi);
     
        for (i = 0; i < 4; i++)
          {  x = 100+i*40;
             y = 148-(auct->needlevel[i]*2);
             drawcolor = 8;
             aline (x-12,y-1,x+12,y-1);
     
             count = auct->amount[i]-auct->needlevel[i];
             if (count > 0)
               {  auct->seller[i] = 1;
                  auct->ypos[i] = 63;
               }
             else
               {  auct->seller[i] = 0;
                  auct->ypos[i] = 167;
               }
             itoa (count, rivi, 10);
             drawcolor = 0;
             bbar (x-15,175,x+15,185);
             writemid (x,175, rivi);
          }
     
        flip();
     
        delayi (idelaytime);

        // SELL/BUY DECLARATION---------------------------------------------
        drawcolor = 0; bbar (0,0,319,199);

        writemid (160,5,"PRESS DOWN OR UP TO DECLARE");
        writemid (160,15,"YOURSELF AS A BUYER OR A SELLER");
        
        putnpic (30-11,5,stockpic1);
        putnpic (290-11,5,stockpic2);

        landgrand_count = landgrand_accelerate = 0;

        changed = 1;

          // time bar
        ly = 112;
        drawcolor = 0xb6; aline (300,122,300,162);
        drawcolor = 0xb2; aline (301,122,301,162);
        drawcolor = 0xb4; aline (302,122,302,162);
        drawcolor = 0xb7; aline (303,122,303,162);
        drawcolor = 0xba; aline (304,122,304,162);

        while (!exitgame)
          {  y = 122+(landgrand_count/2);
             if (y != ly)
               {  drawcolor = 0; bbar (300,ly,305,y); ly = y;
                  changed++;
               }

             if (changed)
               {  for (i = 0; i < 4; i++)
                    {  x = 100+i*40;
                       bbar (x-15, 63-33, x+15,63);
                       bbar (x-15, 168-25, x+15,168+5);
                       if (auct->seller[i])
                         {  putpiccolorize (x-11, 63-25, racesprites[(int)plrrace[i]][4+2],colortable2[i+1] );
                            writemid (x,63-33,"SELL");
                         }
                       else
                         {  putpiccolorize (x-11, 168-25, racesprites[(int)plrrace[i]][4+0],colortable2[i+1] );
                            writemid (x,168,"BUY");
                         }
                    }
                  changed = 0;
                  flip();
               }

             readjoy();
             for (i = 0; i < 4; i++)
               {  if (getk(i,K_UP))
                    {  auct->seller[i] = 1; setk(i,K_UP,0);
                       auct->ypos[i] = 63;
                    }
                  if (getk(i,K_DOWN))
                    {  auct->seller[i] = 0; setk(i,K_DOWN,0);
                       auct->ypos[i] = 168;
                    }
               }

             if (landgrand_count > 80) break;
               
             check_shutdown();
             if (exitgame) return;  
          }
    } // goods amount changes
  else
    {  // land auct; all buy (but who one sells)
       for (i = 0; i < 4; i++)
         if (auct->landseller == i)
           auct->seller[i] = 1;
         else
           auct->seller[i] = 0;
    }


  // -------------------------------------------------AUCTION
   spritedest = backg;
   sprintf (rivi,"%s AUCTION #%i",auct_names[auct->aucttype],month);
   writemid (160,5,rivi);
   putnpic (30-11,5,stockpic1);
   putnpic (290-11,5,stockpic2);

   writeleft (80-10,175,"Traded:");

   spritedest = ruutu;

   memmove (ruutu,backg,64000);

   // time bar
   ly = 68;
   drawcolor = 0xb6; aline (300,68,300,162);
   drawcolor = 0xb2; aline (301,68,301,162);
   drawcolor = 0xb4; aline (302,68,302,162);
   drawcolor = 0xb7; aline (303,68,303,162);
   drawcolor = 0xba; aline (304,68,304,162);

   for (i = 0; i < 4; i++)
     {  step[i] = 6;
        traded[i] = 0;
        tradewith[i] = -1; //none
     }

   landgrand_count = 0;
   changed = 1;

   selling = buying = -1;

   sellcounter = 0;


   strcpy (auctmessage,"");
   auctmessagetime = 0;

   pricespeed = 1 / (price_to_y (1, auct) - price_to_y (2, auct) );
   f = 0;
   
   while ( (!exitgame) )
     {
         // time bar
        y = 68+(landgrand_count / (2000/95) );
        if (y != ly)
          {  drawcolor = 0; bbar (300,ly,305,y); ly = y;
             changed |= 1;
          }

        if (landgrand_count >= 2000)
          break;

         // auctmessage defined; timeout occured -> force changed
        if ( (!auctmessagetime) && (auctmessage[0] != 0) )
          changed++;

        if (changed)
          {    // restore background image
             movememo (20,15, 280,170, backg,ruutu);

             if (auctmessagetime)
               {  writemid (160,15,auctmessage);
               }
             else
               auctmessage[0] = 0;

               // buy-line; shop / highest buying player; always exists
             buy_y = 163;
             putnpic (80-50,163-16,shoppic);
             for (i = 0; i < 4; i++)
               if ( (auct->ypos[i] < buy_y) && (auct->seller[i]==0) ) buy_y = auct->ypos[i];
               
             putnpic (80,buy_y-1,buyline);
             y_to_price (buy_y, auct, rivi);
             writef (240+1,buy_y-4,rivi,1);

              // sell-line; shop / lowest selling player; if nothing in shop, doesn't necessarily exists
             sell_y = -1;
             for (i = 0; i < 4; i++)
               if ( (auct->ypos[i] > sell_y) && (auct->seller[i]==1) && (auct->ypos[i] >= 67) ) sell_y = auct->ypos[i];
             if ( (auct->shopamount) && (sell_y < 67) ) sell_y = 67; // no shop; no line
               
             if (sell_y != -1)
               {  putnpic (80,sell_y-1, sellline);
                  y_to_price (sell_y, auct, rivi);
                  if (auct->shopamount)
                    putnpic (240+50-27,67-16,shoppic);
                  writeleft (80-1,sell_y-4,rivi);
               }

             for (i = 0; i < 4; i++)
               {  if (auct->seller[i]) z = 2; else z = 0;
                  putpiccolorize (100+i*40-11, auct->ypos[i]-25,
                           racesprites[(int)plrrace[i]][get_step2(&step[i])+z],colortable2[i+1] );
                  itoa (traded[i], rivi, 10);
                  writemid (100+i*40,175, rivi);
               }

             flip();
          }


        if (counter == 0)
          {   // selling: min =  63(abs),  67(offer)
              //          max = 163(absolute)
              // buying:  min =  67(absolute)
              //          max = 163(offer), 168(abs)

              // player movement

             accel = 1;

             readjoy();
             for (i = 0; i < 4; i++)
               {  if (auct->seller[i]) // plr SELLING
                    {  if (getk(i,K_UP)) // seller retreats (up)
                         {  changed++;
                            if (auct->ypos[i] > 63)
                              {  auct->ypos[i]--;
                                 if (auct->ypos[i] > 66) accel = 0;
                              }
                            step[i]++;
                         }

                       if (getk(i,K_DOWN)) // seller advances (down)
                         {  changed++;
                            if (auct->ypos[i] < 163)
                              if ( (buying == -1) || (auct->ypos[buying] > auct->ypos[i]) )
                                if ( (auct->amount[i] > 0) || (auct->ypos[i] < 66) ) // if goods
                                  auct->ypos[i]++;
                            step[i]++;
                            accel = 0;
                         }
                    }
                  else // plr BUYING
                    {  if (getk(i,K_UP)) // buyer advances (up)
                         {  changed++;
                            if (auct->ypos[i] > 67)
                              {  if ( (selling == -1) || (auct->ypos[selling] < auct->ypos[i]) )
                                   if ( (plr_money[i] > y_to_price(auct->ypos[i],auct,rivi)) || (auct->ypos[i] > 164) ) // money available?
                                     {  auct->ypos[i]--;
                                        if (auct->ypos[i] < 164) accel = 0;
                                     }
                              }
                            else
                              {  if ( (auct->shopamount == 0) && (selling == -1) ) // limit&shop empty; increase price
                                   {
                                      f += pricespeed;
                                      if (f > 1)
                                        {  auct->shopbuyprice++;
                                           auct->shopsellprice++;
                                           f -= 1;
                                        }
                                      accel = 0;
                                   }
                              }
                            step[i]++;
                         }

                       if (getk(i,K_DOWN)) // buyer retreats (down)
                         {  changed++;
                            if (auct->ypos[i] < 168)
                              auct->ypos[i]++;
                            step[i]++;
                         }
                    } // if seller else
               } // for i=0 to 4

             // pick selling plr
             y = 67;
             selling = -1;
             for (i = 0; i < 4; i++)
               if ( (auct->seller[i]) && (auct->ypos[i] >= y) )
                 {  selling = i;  }

             for (i = 0; i < 4; i++)
               if (i != selling)
                 tradespeed[i] = 0;

             // pick buying plr
             y = 163;
             buying = -1;
             for (i = 0; i < 4; i++)
               if ( (!auct->seller[i]) && (auct->ypos[i] <= y) )
                 {  buying = i;  }

             if ( (selling != -1) && (buying != -1) ) // players trading
               {  if (auct->ypos[selling] == auct->ypos[buying])
                    {  accel = 0;
                       if (!sellcounter)
                         {  playsound(SND_TIMETICK,22050); // todo: vaihda sample
                         
                            sellcounter = 25 - tradespeed[selling]*3;
                            if (tradespeed[selling] < 7) tradespeed[selling]++;

                            price = y_to_price(sell_y,auct,rivi);

                            auct->amount[selling]--;
                            plr_money[selling] += price;
                            traded[selling]++;

                            if (auct->amount[selling] <= 0)
                              {  auctmessagetime = 50;
                                 strcpy (auctmessage, "Seller ran out of goods");
                                 auct->ypos[selling] = 63;
                              }
                            else
                              {  auct->amount[buying]++;
                                 plr_money[buying] -= price;
                                 traded[buying]++;
                                 if (plr_money[buying] < price)
                                   {  auctmessagetime = 50;
                                      strcpy (auctmessage, "Buyer can't afford the price");
                                      auct->ypos[selling] = 168;
                                   }
                              }

                            changed++;
                         } // if !sellcounter
                    } // if ypos[buy]==ypos[sell]
               } // if selling && buying ; players trading
             else
               {  // players not trading; check shop trade
                  if ( (selling != -1) && (auct->ypos[selling] == 163) )
                    {  // player selling to shop
                       accel = 0;
                       if (!sellcounter)
                         {  playsound(SND_TIMETICK,22050); // todo: vaihda sample
                            price = y_to_price (sell_y,auct,rivi);

                            sellcounter = 25 - tradespeed[selling]*3;
                            if (tradespeed[selling] < 7) tradespeed[selling]++;

                            auct->amount[selling]--;
                            plr_money[selling] += price;
                            traded[selling]++;

                            if (auct->amount[selling] <= 0)
                              {  auctmessagetime = 50;
                                 strcpy (auctmessage, "Seller ran out of goods");
                                 auct->ypos[selling] = 63;
                              }
                            else
                              {  auct->shopamount++;
                              }

                            changed++;
                         }
                    } // if selling && ypos=shop

                    // player buying from shop
                  if ( (buying != -1) && (auct->ypos[buying] == 67) && (auct->shopamount) )
                    {  // player selling to shop
                       accel = 0;
                       if (!sellcounter)
                         {  playsound(SND_TIMETICK,22050); // todo: vaihda sample
                            price = y_to_price (sell_y,auct,rivi);

                            sellcounter = 25 - tradespeed[buying]*3;
                            if (tradespeed[buying] < 7) tradespeed[buying]++;

                            auct->amount[buying]++;
                            plr_money[buying] -= price;
                            traded[buying]++;

                            if (plr_money[buying] < price)
                              {  auctmessagetime = 50;
                                 strcpy (auctmessage, "Buyer can't afford the price!");
                                 auct->ypos[buying] = 63;
                              }
                            else
                              {  auct->shopamount--;
                                 if (auct->shopamount <= 0)
                                   {  auctmessagetime = 50;
                                      strcpy (auctmessage, "Shop ran out of goods!");
                                   }
                              }

                            changed++;
                         }
                    }

               }


             counter = 2;
             landgrand_accelerate = accel;
          }
          
        check_shutdown();
     }

   playwithdelay (SND_BELL,22050,20);
   playwithdelay (SND_BELL,22050,20);
   playwithdelay (SND_BELL,22050,20);
}

// ***************************************************************
void show_auction(char *name, int picypos)
{  int i,count,x,y,ly,z,n,ii;
   int spoilc[4],sellbuy[4],ypos[4],price[4],
       notmoved,highestbuy,lowestsell,shopbuys,traded[4],
       advance,retreat;

   int auctgood; // which; R_FOOD etc
   float p; // analyzed price

   int cdo[4]; // computer do
   int camount[4]; // amount
   int sellprice, buyprice;

   volatile int step[5];

   int comp_wants[4],comp_wantamount[4];

   if (exitgame) return;

   timer_routine = landgrand_timerrout;

   purakuva ("auct.dat", ruutu2);
   purakuva ("auctb.dat", backg);

   spritedest = ruutu2;
   getpic (86,117,99,117,stockbar);
   getpic (71,101,231,103,sellline);
   getpic (71,105,231,107,buyline);
   getpic (1, picypos,1+22, picypos+22, stockpic1);
   getpic (25,picypos,25+22,picypos+22, stockpic2);
   getpic (49,1,75,18,shoppic);
/*   drawcolor = 0;
   bbar (57,108, 233,120);
   bbar (67,51, 239,149);
   bbar (0,0, 48,100); */
   spritedest = ruutu;

   memmove (ruutu, backg, 64000);
   setpale (64,64,64);

   writemid (160,10,"STOCK CHANGES DURING THE MONTH");

   strcpy (rivi, name);
   strcat (rivi, " IN STOCK");
   drawcolor = 0; bbar (0,30,319,40);
   writemid (160,30,rivi);

   putnpic (30-11,5,stockpic1);
   putnpic (290-11,5,stockpic2);

   drawcolor = 8;
   aline (70,148,250,148);

   for (i = 0; i < 4; i++)
     {  putpiccolorize (85+i*45,150,racesprites[(int)plrrace[i]][4+2],colortable2[i+1] );
        itoa (aucts.plrgoods[i], rivi, 10);
        writemid (97+i*45,175, rivi);
        drawcolor = 7;
        y = 147-(aucts.plrgoods[i]*2); if (y < 57) y = 57;
        sabar (90+i*45,y ,104+i*45,147);
     }
   flip();

   delayap (idelaytime);

   for (i = 0; i < 4; i++) step[i] = 8;

   // -----------------USAGE
   strcpy (rivi, name);
   strcat (rivi, " USED");
   drawcolor = 0; bbar (0,30,319,40);
   writemid (160,30,rivi);
   putnpic (30-11,5,stockpic1);
   putnpic (290-11,5,stockpic2);

   count = 0;
   for (i = 0; i < 4; i++)
     if (aucts.plrusage[i] > count) count = aucts.plrusage[i];

   flip();
   landgrand_count = 0;
   while (count > 0 && !exitgame)
     {  if (landgrand_count > 1)
          {  for (i = 0; i < 4; i++)
               if (aucts.plrusage[i])
                 {  aucts.plrgoods[i]--;
                    aucts.plrusage[i]--;
                    x = 90+i*45;
                    y = 145-(aucts.plrgoods[i]*2);
                    if (y > 56)
                      bbar (x,y,x+14,y+1);

                    bbar (x-10,175,x+20,185);
                    itoa (aucts.plrgoods[i], rivi, 10);
                    writemid (x+7,175, rivi);
                 }
             landgrand_count = 0;
             count--;
             flip();
             
          }
        check_shutdown();
        if (exitgame) return;
     }

   delayap (idelaytime);

   // -----------------SPOILED
   strcpy (rivi, name);
   strcat (rivi, " SPOILED");
   drawcolor = 0; bbar (0,30,319,40);
   writemid (160,30,rivi);
   putnpic (30-11,5,stockpic1);
   putnpic (290-11,5,stockpic2);

   for (i = 0; i < 4; i++)
     {  spoilc[i] = 0;
        if (aucts.plrgoods[i] > aucts.spoilmin)
          spoilc[i] = (int) ((float) (aucts.plrgoods[i]-aucts.spoilmin) * aucts.spoillevel);
     }

   count = 0;
   for (i = 0; i < 4; i++)
     if (spoilc[i] > count) count = spoilc[i];

   flip();
   landgrand_count = 0;
   while (count > 0 && !exitgame)
     {  if (landgrand_count > 1)
          {  for (i = 0; i < 4; i++)
               if (spoilc[i])
                  {  aucts.plrgoods[i]--;
                     spoilc[i]--;
                     x = 90+i*45;
                     y = 145-(aucts.plrgoods[i]*2);
                     if (y > 56)
                       bbar (x,y,x+14,y+1);


                     bbar (x-10,175,x+20,185);
                     itoa (aucts.plrgoods[i], rivi, 10);
                     writemid (x+7,175, rivi);
                  }
             landgrand_count = 0;
             count--;
             flip();

          }
        check_shutdown();
        if (exitgame) return;
     }

   delayap (idelaytime);

      // -----------------PRODUCED
   strcpy (rivi, name);
   strcat (rivi, " PRODUCTION");
   drawcolor = 0; bbar (0,30,319,40);
   writemid (160,30,rivi);
   putnpic (30-11,5,stockpic1);
   putnpic (290-11,5,stockpic2);

   count = 0;
   for (i = 0; i < 4; i++)
     if (aucts.plrprod[i] > count) count = aucts.plrprod[i];

   flip();
   landgrand_count = 0;
   while (count > 0 && !exitgame)
     {  if (landgrand_count > 1)
          {  for (i = 0; i < 4; i++)
               if (aucts.plrprod[i])
                  {  aucts.plrgoods[i]++;
                     aucts.plrprod[i]--;
                     x = 90+i*45;
                     y = 147-(aucts.plrgoods[i]*2);
                     drawcolor = 7;
                     if (y > 56)
                       sabar (x,y,x+14,y+1);

                     drawcolor = 0;
                     bbar (x-10,175,x+20,185);
                     itoa (aucts.plrgoods[i], rivi, 10);
                     writemid (x+7,175, rivi);
                  }
             landgrand_count = 0;
             count--;
             flip();
          }
        check_shutdown();
        if (exitgame) return;
     }

   delayap (idelaytime);

   //---final stock
   strcpy (rivi, name);
   strcat (rivi, " LEVEL");
   drawcolor = 0; bbar (0,30,319,40);
   writemid (160,30,rivi);
   putnpic (30-11,5,stockpic1);
   putnpic (290-11,5,stockpic2);

   sprintf (rivi,"STORE HAS %i UNITS", aucts.storeamount);
   writemid (160,187,rivi);

   for (i = 0; i < 4; i++)
     {  x = 90+i*45;
        y = 148-(aucts.plrneed[i]*2);
        drawcolor = 8;
        aline (x-7,y-1,x+21,y-1);

        spoilc[i] = aucts.plrgoods[i]-aucts.plrneed[i];
        if (spoilc[i] > 0)
          sellbuy[i] = A_SELL;
        else
          sellbuy[i] = A_BUY;
        itoa (spoilc[i], rivi, 10);
        drawcolor = 0;
        bbar (x-10,175,x+20,185);
        writemid (x+7,175, rivi);
     }

   flip();

   delayi (idelaytime);

/*   sellbuy[0] = 0;
   sellbuy[1] = 0;
   sellbuy[2] = 0;
   sellbuy[3] = 0; */

   //------------AUCTION-----------------------
   memmove (ruutu, backg, 64000);


   putnpic (34,148,shoppic);

   if (aucts.storeamount != 0)
     {  itoa (aucts.storesellprice,rivi,10); // price store sells
        putnpic (268,52,shoppic);
        writemid (280,70,rivi);
     }
   itoa (aucts.storebuyprice,rivi,10); // price store buys
   writemid (46,166,rivi);


   ly = 112;
   drawcolor = 0xb6; aline (300,122,300,162);
   drawcolor = 0xb2; aline (301,122,301,162);
   drawcolor = 0xb4; aline (302,122,302,162);
   drawcolor = 0xb7; aline (303,122,303,162);
   drawcolor = 0xba; aline (304,122,304,162);

   drawcolor = 0;
   bbar (0,0,319,50);
   writemid (160,5,"PRESS DOWN OR UP TO DECLARE");
   writemid (160,15,"YOURSELF AS A BUYER OR A SELLER");
   putnpic (30-11,5,stockpic1);
   putnpic (290-11,5,stockpic2);

   for (i = 0; i < 4; i++)
     {  x = 85+i*45;
        traded[i] = 0;

        if (sellbuy[i] == A_SELL) { y = 64-23; z = 2; } else { y = 169-23; z = 0; }
        putpiccolorize (x,y,racesprites[(int)plrrace[i]][4+z],colortable2[i+1] );
        if (sellbuy[i] == A_SELL)
          {  writemid (x+12,29,"SELL");
             bbar (x,166,x+25,186);
          }
        else
          {  writemid (x+12,169,"BUY");
             bbar (x,28,x+25,38);
          }
        if (sellbuy[i] == A_BUY) { y = 64-23; z = 2; } else { y = 169-23; z = 0; }

     }


   flip();

   landgrand_accelerate = landgrand_count = 0;
   while (1 && !exitgame)
     {  y = 122+(landgrand_count/2);
        if (y != ly)
          {  drawcolor = 0; bbar (300,ly,305,y); ly = y;
             changed++;
          }

        readjoy();
        for (i = 0; i < 4; i++)
          {  x = 85+i*45;
             if (getk(i,K_UP))
               {  changed++; sellbuy[i] = A_SELL;
                  putpiccolorize (x,64-23,racesprites[(int)plrrace[i]][4+2],colortable2[i+1] );
                  drawcolor = 0; bbar (x-2,167-24,x+27,167-24+35);
                  writemid (x+12,29,"SELL");
               }
             if (getk(i,K_DOWN))
               {  changed++; sellbuy[i] = A_BUY;
                  putpiccolorize (x,168-23,racesprites[(int)plrrace[i]][4+0],colortable2[i+1] );
                  drawcolor = 0; bbar (x-2,29,x+27,29+35);
                  writemid (x+12,167,"BUY");
               }
          }
          
        if (changed) { flip(); changed = 0; }
        if (landgrand_count > 80) break;

        check_shutdown();
        if (exitgame) return;
     }
   flip();

   z = 0;
   for (i = 0; i < 4; i++)
     if (sellbuy[i] == A_SELL) z++;
   if (aucts.storeamount) z++;

   if (z == 0)
     {  drawcolor = 0; bbar (0,90,319,100);
        writemid (160,90,"NO SELLERS - NO AUCTION");
        flip();
        playwithdelay (SND_BELL,22050,20);
        playwithdelay (SND_BELL,22050,20);
        playwithdelay (SND_BELL,22050,20);
        delayap (idelaytime);
        timer_routine = NULL;
        return;
     }

     //***************************

   // picypos 1=ore,25=energy,49=food,73=cryst
   // computer analyze situation

   for (i = 0; i < 4; i++)
     {  comp_wants[i] = 0; camount[i] = 0;  cdo[i] = 0; }

   if (picypos == 25) // ENERGY
     auctgood = R_ENERGY;
/*     for (i = 0; i < 4; i++)
       {  if (!plrcontrol[i])
             {  if (aucts.plrgoods[i] < aucts.plrneed[i] - 2)
                  comp_wants[i] = 10; // dire straits!
                else
                  if (aucts.plrgoods[i] < aucts.plrneed[i] - 1)
                    comp_wants[i] = 5; // needs, yes
                  else
                    if (aucts.plrgoods[i] < aucts.plrneed[i])
                      comp_wants[i] = 1; // well...
                    else
                      comp_wants[i] = 0;
                if (aucts.plrgoods[i] < aucts.plrneed[i])
                  comp_wantamount[i] = aucts.plrneed[i]-aucts.plrgoods[i];
                // sell away, it rots
                if ( (aucts.plrgoods[i] > aucts.spoilmin-20) && ( aucts.plrgoods[i] > 20) )
                  {  comp_wants[i] = -1;
                     comp_wantamount[i] = - aucts.plrgoods[i] - aucts.spoilmin - 5;
                  }
                comp_pays[i] = aucts.storesellprice*2;
             }

       } */

   if (picypos == 49) // FOOD
     {  auctgood = R_FOOD;
/*        for (i = 0; i < 4; i++)
          {  if (!plrcontrol[i])
                {  if (aucts.plrgoods[i] < aucts.plrneed[i] - 5)
                     comp_wants[i] = 10; // dire straits!
                   else
                     if (aucts.plrgoods[i] < aucts.plrneed[i] - 2)
                       comp_wants[i] = 5; // needs, yes
                     else
                       if (aucts.plrgoods[i] < aucts.plrneed[i])
                         comp_wants[i] = 1; // well...
                       else
                         comp_wants[i] = 0; // forget it
                   if (aucts.plrgoods[i] < aucts.plrneed[i])
                     comp_wantamount[i] = aucts.plrneed[i]-aucts.plrgoods[i];

                    // sell away, it rots
                   if ( (aucts.plrgoods[i] > aucts.spoilmin-20) && ( aucts.plrgoods[i] > 20) )
                     {  comp_wants[i] = -1;
                        comp_wantamount[i] = - aucts.plrgoods[i] - aucts.spoilmin - 5;
                     }
                   comp_pays[i] = aucts.storesellprice*2;
                }
          } */
     }

   // ore: sell if rots
   if (picypos == 1)
     {  auctgood = R_ORE;
/*        for (i = 0; i < 4; i++)
          if (!plrcontrol[i])
            {
               if ( (aucts.plrgoods[i] > aucts.spoilmin-20) && ( aucts.plrgoods[i] > 20) )
                 {  comp_wantamount[i] = aucts.plrgoods[i] - aucts.spoilmin - 5;
                    comp_wants[i] = -1;
                 }
               if ( (plr_money[i] < 200) && (aucts.plrgoods[i] > 0) )
                 {  comp_wants[i] = -1;
                    comp_wantamount[i] = -aucts.plrgoods[i];
                    if (comp_wantamount[i] < -10) comp_wantamount[i] = -10;
                 }
               if (aucts.storeamount < 10) // play safeto to get mules
                 {  comp_wants[i] = -1;
                    comp_wantamount[i] = - (10-aucts.storeamount);
                    if (comp_wantamount[i] < -aucts.plrgoods[i])
                      comp_wantamount[i] = -aucts.plrgoods[i];
                    if (comp_wantamount[i] == 0) comp_wants[i] = 0;
                 }
         } */
     }
   // cryst: sell if rots
   if (picypos == 73)
     {  auctgood = R_CRYSTAL;
/*        comp_wants[i] = 0;
       for (i = 0; i < 4; i++)
       if (!plrcontrol[i])
         {  if ( (aucts.plrgoods[i] > aucts.spoilmin-20) && ( aucts.plrgoods[i] > 20) )
              {  comp_wants[i] = -1;
                 comp_wantamount[i] = aucts.plrgoods[i] - aucts.spoilmin - 5;
              }
            if ( (plr_money[i] < 500) && (aucts.plrgoods[i] > 0) )
              {  comp_wants[i] = -1;
                 comp_wantamount[i] = -aucts.plrgoods[i]-0;
                 if (comp_wantamount[i] < -10) comp_wantamount[i] = -1;
              }
         } */
     }

     // ------last turn - do NOTHINT
   if (month == game_length)
     {  for (i = 0; i < 4; i++)
          {  comp_wants[i] = 0;
             comp_wantamount[i] = 0;
             camount[i] = 0;
          }
     }

   drawcolor = 0;
   bbar (0,0,319,50);
   sprintf (rivi, "%s AUCTION #%i",name,month);
   writemid (160,5,rivi);

   putnpic (30-11,5,stockpic1);
   putnpic (290-11,5,stockpic2);

   for (i = 0; i < 4; i++)
     if (sellbuy[i] == A_SELL)
       {  price[i] = ytoprice (62);
          ypos[i] = pricetoy(price[i]);
          putpiccolorize (85+i*45,ypos[i]-23,racesprites[(int)plrrace[i]][4+2],colortable2[i+1] );
       }
     else
       {  price[i] = ytoprice (168);
          ypos[i] = pricetoy(price[i]);
          putpiccolorize (85+i*45,ypos[i]-23,racesprites[(int)plrrace[i]][4+0],colortable2[i+1] );
       }

   ly = 68;
   drawcolor = 0xb6; aline (300,68,300,162);
   drawcolor = 0xb2; aline (301,68,301,162);
   drawcolor = 0xb4; aline (302,68,302,162);
   drawcolor = 0xb7; aline (303,68,303,162);
   drawcolor = 0xba; aline (304,68,304,162);

   landgrand_count = 0;
   landgrand_accelerate = 0;
   changed = 3;

   highestbuy = -1;
   lowestsell = -1;

   shopbuys = 1;
   sellcounter = -1;

   auctmessagetime = 0;

   flip();
   delay (50);

#define CDO_NONE 0
#define CDO_SELL 1
#define CDO_AFTERSELL 2
#define CDO_BUY 3
#define CDO_AFTERBUY 4
#define CDO_SLOWBUY 5
#define CDO_SELLNOTHING 6
#define CDO_NOTHING 7  // ABSOLUTELY nothing

   while (1 && !exitgame)
     {  y = 68+(landgrand_count / (2000/95) );
        if (y != ly)
          {  drawcolor = 0; bbar (300,ly,305,y); ly = y;
             changed |= 1;
          }

        if (landgrand_count < 2000)
          {  timetick_speed = 150- (145 * landgrand_count / 2000);
          }

        if (landgrand_count > 2000) break;

        if (!counter)
          { counter = 3;
            // player controls
            notmoved = 1;
            readjoy();

              // get highest buy offer price
            if (highestbuy == -1)
              buyprice = aucts.storebuyprice; // no one, so shop
            else
              buyprice = price[highestbuy]; // someone

            if (lowestsell == -1)
              {  if (aucts.storeamount <= 0)
                   sellprice = 90000; // nothing to buy
                 else
                   sellprice = aucts.storesellprice;
              }
            else
              sellprice = price[lowestsell];
            
            for (i = 0; i < 4; i++)
              {  advance = retreat = 0;
                 if (!plrcontrol[i]) // computer
                   {  if (month == game_length)
                        cdo[i] = CDO_NOTHING;

                      if (!cdo[i])
                        switch (auctgood)
                          {  case R_FOOD    : if (sellbuy[i] == A_SELL)
                                                {  computer_analyze_food_sell (i, &p, &n, buyprice );
                                                   if (p < 1)
                                                     cdo[i] = CDO_NONE;

                                                   if (n > aucts.spoilmin)
                                                     {  cdo[i] = CDO_SELL;
                                                        camount[i] = n-aucts.spoilmin;
                                                     }

                                                   if (n <= 0)
                                                     cdo[i] = CDO_SELLNOTHING;
                                                }
                                              if (sellbuy[i] == A_BUY)
                                                {  computer_analyze_food_sell (i, &p, &n, sellprice );
                                                   if (n < -3)
                                                     {  if (p < 2.0-comp_pricelevel[i])
                                                          {  cdo[i] = CDO_SLOWBUY; camount[i] = 1; }
                                                     }

                                                   if (n == -3)
                                                     {  if (p < 1.7-comp_pricelevel[i])
                                                          {  cdo[i] = CDO_SLOWBUY; camount[i] = 1; }
                                                     }
                                                   if (n == -2)
                                                     {  if (p < 1.4-comp_pricelevel[i])
                                                          {  cdo[i] = CDO_SLOWBUY; camount[i] = 1; }
                                                     }
                                                   if (n == -1)
                                                     {  if (p < 1.1-comp_pricelevel[i])
                                                          {  cdo[i] = CDO_SLOWBUY; camount[i] = 1; }
                                                     }
                                                   if ( (n == 0) && (price[i] > aucts.storebuyprice) )
                                                     cdo[i] = CDO_AFTERBUY;

                                                   if (plr_money[i] < sellprice) cdo[i] = 0;
                                                }
                                              break; // R_FOOD food-ai

                             case R_ENERGY  : if (sellbuy[i] == A_SELL)
                                                {  computer_analyze_energy_sell (i, &p, &n, buyprice );
                                                   if (p < 1)
                                                     cdo[i] = CDO_NONE;

                                                   if (n > aucts.spoilmin)
                                                     {  cdo[i] = CDO_SELL;
                                                        camount[i] = n-aucts.spoilmin;
                                                     }

                                                   if (n <= 0)
                                                     cdo[i] = CDO_SELLNOTHING;  
                                                }
                                              if (sellbuy[i] == A_BUY)
                                                {  computer_analyze_energy_sell (i, &p, &n, sellprice );
                                                   if (n < -3)
                                                     {  if (p < 2.0-comp_pricelevel[i])
                                                          {  cdo[i] = CDO_SLOWBUY; camount[i] = 1; }
                                                     }

                                                   if (n == -3)
                                                     {  if (p < 1.7-comp_pricelevel[i])
                                                          {  cdo[i] = CDO_SLOWBUY; camount[i] = 1; }
                                                     }
                                                   if (n == -2)
                                                     {  if (p < 1.4-comp_pricelevel[i])
                                                          {  cdo[i] = CDO_SLOWBUY; camount[i] = 1; }
                                                     }
                                                   if (n == -1)
                                                     {  if (p < 1.1-comp_pricelevel[i])
                                                          {  cdo[i] = CDO_SLOWBUY; camount[i] = 1; }
                                                     }
                                                   if ( (n >= 0) && (price[i] > aucts.storebuyprice) )
                                                     cdo[i] = CDO_AFTERBUY;

                                                   if (plr_money[i] < sellprice) cdo[i] = 0;

                                                }
                                              break; // R_ENERGY energy-ai
                                              
                             case R_ORE     : if (sellbuy[i] == A_SELL)
                                                {  computer_analyze_ore_sell (i, &p, &n, buyprice );
                                                   if (p < 1)
                                                     cdo[i] = CDO_NONE;
                                                   else
                                                     if (p > 1.3)
                                                       {  cdo[i] = CDO_SELL;
                                                          if (p > 1.3) camount[i] = 4;
                                                          if (p > 1.5) camount[i] = 10;
                                                          if (p > 1.8) camount[i] = 30;
                                                       }

                                                   if ((n > aucts.spoilmin-20) && (!cdo[i]))
                                                     {  cdo[i] = CDO_SELL;
                                                        camount[i] = 20;
                                                        if (camount[i] > n) camount[i] = n;
                                                     }

                                                   if (plr_money[i] < 500)
                                                     {  cdo[i] = CDO_SELL;
                                                        camount[i] = 10;
                                                        if (camount[i] > n) camount[i] = n;
                                                     }

                                                   if (cdo[i] == 0)
                                                     {  if (price[i] <= aucts.storebuyprice)
                                                          cdo[i] = CDO_AFTERSELL;
                                                     }

                                                   if (n <= 0)
                                                     cdo[i] = CDO_SELLNOTHING;
                                                }
                                              if (sellbuy[i] == A_BUY)
                                                {  computer_analyze_ore_sell (i, &p, &n, sellprice );
                                                   if (p < 0.8)
                                                     {  cdo[i] = CDO_BUY;
                                                        camount[i] = ((plr_money[i]-400) / sellprice );
                                                        if (camount[i] <= 2)
                                                          cdo[i] = CDO_NONE;

                                                     }
                                                   if (plr_money[i] < sellprice) cdo[i] = 0;
                                                }
                                              break; // R_ORE ore-ai

                             case R_CRYSTAL : if (sellbuy[i] == A_SELL)
                                                {  computer_analyze_crystal_sell (i, &p, &n, buyprice );
                                                   if (p < 1)
                                                     {  cdo[i] = CDO_NONE;  }
                                                   else
                                                     if (p > 1.3)
                                                       {  cdo[i] = CDO_SELL;
                                                          if (p > 1.3) camount[i] = 2;
                                                          if (p > 1.5) camount[i] = 5;
                                                          if (p > 1.7) camount[i] = 10;
                                                          if (p > 1.9) camount[i] = 20;
                                                          if (p > 2.1) camount[i] = 100;
                                                       }

                                                   if ((n > aucts.spoilmin-20)  && (!cdo[i]))
                                                     {  cdo[i] = CDO_SELL;
                                                        camount[i] = 20;
                                                        if (camount[i] > n) camount[i] = n;
                                                     }

                                                   if (plr_money[i] < 500)
                                                     {  cdo[i] = CDO_SELL;
                                                        camount[i] = 10;
                                                        if (camount[i] > n) camount[i] = n;
                                                     }

                                                   if (cdo[i] == 0)
                                                     {  if (price[i] <= aucts.storebuyprice)
                                                          cdo[i] = CDO_AFTERSELL;
                                                     }
                                                   if (n <= 0)
                                                     cdo[i] = CDO_SELLNOTHING;
                                                }
                                              if (sellbuy[i] == A_BUY)
                                                {  computer_analyze_crystal_sell (i, &p, &n, sellprice );
                                                   if (p < 0.8)
                                                     {  cdo[i] = CDO_BUY;
                                                        camount[i] = ((plr_money[i]-400) / sellprice );
                                                        if (camount[i] <= 2)
                                                          cdo[i] = CDO_NONE;

                                                     }
                                                   if (plr_money[i] < sellprice) cdo[i] = 0;
                                                }
                                              break; // R_CYSTAL crist-ai crystal-ai cryst-ai cristite-ai
                          }

                      if (camount[i] < 0) camount[i] = 0;
                      switch (cdo[i])
                        {//case 0 : break; // nothing
                           case 1 : // selladvance, sells goods
                                    if (price[i] > buyprice)
                                      retreat++;
                                    if (aucts.plrgoods[i] <= aucts.plrneed[i])
                                      cdo[i] = 0; // no more
                                    if (!camount[i]) // sold all it wanted to sell
                                      cdo[i] = 2;
                                    break;
                                    
                           case 2 : // sellretreat, doesn't want to sell
                                    advance++;
                                    if (price[i] > aucts.storebuyprice)
                                      cdo[i] = 0;
                                    break;

                           case 3 : // buy
                                    advance++;
                                    if (!camount[i]) cdo[i] = CDO_AFTERBUY;
                                    break;

                           case 4 : // buyretreat
                                    retreat++;
                                    if (price[i] < aucts.storesellprice)
                                      cdo[i] = 0;
                                    break;

                           case 5 : // buy
                                    advance++;
                                    if (!camount[i]) cdo[i] = 0;
                                    break;
                           case 6 : if (price[i] < aucts.storesellprice)
                                      advance++;
                                    break;
                           case 7 : break; // NOTHING
                        }

/*                      if (comp_wantamount[i] == 0)
                        {  if ( (comp_wants[i] == -1) && (price[i] >= aucts.storesellprice) )
                             advance++;
                           else
                             comp_wants[i] = 0;
                        }
                      if (comp_wants[i] == 10) // in dire straits!
                        {  if (price[i] < comp_pays[i])
                             advance++;
                        }
                      if (comp_wants[i] == 5) // might stall
                        {  if ( ((landgrand_count < 1300) && (ypos[i] > 142)) || (!rand() % 100) ) advance++;
                           if ( ((landgrand_count > 1500) && (ypos[i] > 112)) || (!rand() % 100) ) advance++;
                           if ((landgrand_count > 1600) && (ypos[i] < 100)) advance++;
                           if ((landgrand_count > 1700) && (ypos[i] < 67)) advance++;
                        }
                      if (comp_wants[i] == 1) // stall ...
                        {  if ( (ypos[i] > 142) || (rand() % 100 == 0) ) advance++;
                           if ((landgrand_count > 1700) && (ypos[i] < 67)) advance++;
                        }
                      if (comp_wants[i] < 0) retreat++;

                      if ( (sellbuy[i] == A_BUY) && (comp_wantamount[i] == 0) && (ypos[i] < 164) ) retreat++; */
                   }
                 else
                   {  if (getk(i,K_UP)) advance++;
                      if (getk(i,K_DOWN)) retreat++;
                   }

                 if (advance)
                   {  z = 0;
                      if (sellbuy[i] == A_BUY)
                        {
                           /*for (n=0; n < 4; n++)
                             if ( (sellbuy[n] == A_SELL) &&
                                  (price[n] == price[i]) &&
                                  (price[n] <= aucts.storesellprice) ) z++; // seller at same level, can't get higher*/
                           if ( (aucts.storeamount) && (price[i] == aucts.storesellprice) )
                             z++; // store exists, can't rise
                           else
                             {  for (n = 0; n < 4; n++)
                                  if ( (sellbuy[n] == A_SELL) && (price[n] == price[i]) )
                                    z++; // no shop, buy someone else sells
                             }

                           if ( (price[i] == aucts.storesellprice) && (!aucts.storeamount) && (!z) )
                             {  for (ii=0; ii < 4; ii++)
                                  if (price[ii] > aucts.storesellprice) price[ii]++;
                                aucts.storebuyprice++;
                                aucts.storesellprice++;
                                notmoved = 0;
                                price[i]++;
                                landgrand_count--;
                                changed |= 4;
                                z++;
                             }

                           if (price[i] >= plr_money[i]) z++; // no credits
                           if (!z)  price[i]++;
                         } // if A_BUY
                       else // A_SELL
                         {  if (price[i] < ytoprice(62) ) price[i]++; // gets past the shop,
                         }
                       ypos[i] = pricetoy(price[i]);
                       changed |= 2;
                       if ( (price[i] >= aucts.storebuyprice) &&
                            (price[i] <= aucts.storesellprice) ) notmoved=0;
                   } // if advance

                 if (retreat)
                   {  z = 0;
                      if (sellbuy[i] == A_SELL)
                        {  for (n=0; n < 4; n++)
                             if ( (sellbuy[n] == A_BUY) && (price[n] >= price[i]) )
                               {  if (price[i] <= aucts.storesellprice) z++; // seller at same level, can't get higher
                               }
                           if (price[i] <= aucts.storebuyprice) z++; // can't get past the store
                           if (!aucts.plrgoods[i]) z++; // nothing to sell

                           if (!z)  price[i]--;
                        }
                      else // A_BUY
                        {  if (price[i] > ytoprice(168)) price[i]--; // gets past the shop, barely
                        }

                      ypos[i] = pricetoy(price[i]);
                      changed |= 2;
                      if ( (price[i] >= aucts.storebuyprice) &&
                           (price[i] <= aucts.storesellprice) ) notmoved = 0;
                   } // if retreat

                 if (advance || retreat)
                   {  step[i]++;
                   }
                 else
                   {  step[i] = 7;
                   }
                   
              } // for i

            
            // buy/sell
            for (z=0,i=0; i < 4; i++)
              {  if ( (sellbuy[i] == A_BUY) && (highestbuy == -1) && (price[i] >= aucts.storebuyprice) ) highestbuy = i;
                 if ( (sellbuy[i] == A_BUY) && (highestbuy != -1) && (price[i] > price[highestbuy]) ) highestbuy = i;
                 if (price[i] < aucts.storebuyprice) z++;
              }
            if (z==4) highestbuy = -1;

            for (z=0,i=0; i < 4; i++)
              {  if ( (sellbuy[i] == A_SELL) && (lowestsell == -1) && (price[i] <= aucts.storesellprice) ) lowestsell = i;
                 if ( (sellbuy[i] == A_SELL) && (lowestsell != -1) && (price[i] < price[lowestsell]) ) lowestsell = i;
                 if (price[i] > aucts.storesellprice) z++;
              }
            if (z==4) lowestsell = -1;

            // players trade among themselves
            if ( (lowestsell != -1) && (highestbuy != -1) &&
                 (price[lowestsell] == price[highestbuy]) )
              {  if (sellcounter == -1) sellcounter = 10;
                 if (!sellcounter)
                   {  sellcounter = 10;
                      if (plr_money[highestbuy] < price[highestbuy])
                        {  price[highestbuy] = ytoprice(168);
                           strcpy (auctmessage,"BUYER CAN'T AFFORD THE PRICE");
                           auctmessagetime = 100;
                        }
                      else
                        {  aucts.plrgoods[highestbuy]++; traded[highestbuy]++; comp_wantamount[highestbuy]--;
                           aucts.plrgoods[lowestsell]--; traded[lowestsell]++; comp_wantamount[lowestsell]++;

                           camount[highestbuy]--;
                           camount[lowestsell]++;
                           playsound(SND_TIMETICK,22050); // todo: vaihda sample
                           
                           plr_money[highestbuy] -= price[highestbuy];
                           plr_money[lowestsell] += price[lowestsell];
                           landgrand_count -= 3;
                           notmoved = 0;
                           changed |= 2;
                           play_tradesound();

                           if (aucts.plrgoods[lowestsell] == 0)
                             {  price[lowestsell] = ytoprice(62);
                                strcpy (auctmessage,"SELLER RAN OUT OF GOODS");
                                auctmessagetime = 100;
                             }
                           else
                             if (aucts.plrgoods[lowestsell] == aucts.plrneed[lowestsell])
                               {  price[lowestsell] = ytoprice(62);
                                  strcpy (auctmessage,"SELLER AT CRITICAL LEVEL");
                                  auctmessagetime = 100;
                               }
                        } //else
                  } // if !sellcoutner
              } // if lowestsell ...
            else
              {  z = 0;
                 // player buys from the shop
                 if ( (price[highestbuy] == aucts.storesellprice) && (sellbuy[highestbuy] == A_BUY) && (aucts.storeamount) )
                   {  if (sellcounter == -1) sellcounter = 10;
                      z++;
                      if (!sellcounter)
                        {  sellcounter = 10;
                           if (plr_money[highestbuy] < price[highestbuy])
                             {  price[highestbuy] = ytoprice(168);
                                strcpy (auctmessage,"BUYER CAN'T AFFORD THE PRICE");
                                auctmessagetime = 100;
                             }
                           else
                             {  aucts.plrgoods[highestbuy]++; traded[highestbuy]++; comp_wantamount[highestbuy]--;

                                camount[highestbuy]--;
                             
                                landgrand_count -= 3;
                                plr_money[highestbuy] -= price[highestbuy];
                                play_tradesound();
                                notmoved = 0;
                                aucts.storeamount--;
                                if (aucts.storeamount == 0)
                                  {  sprintf (auctmessage,"NO MORE %s IN STORE", name);
                                     auctmessagetime = 100;
                                  }
                                changed |= 2;
                             }
                        }
                   } // if (price ...

                 // player sells to shop
                 if ( (price[lowestsell] == aucts.storebuyprice) && (sellbuy[lowestsell] == A_SELL) && (shopbuys) )
                   {  if (sellcounter == -1) sellcounter = 10;
                      z++;
                      if (!sellcounter)
                        {  sellcounter = 10;
                           aucts.plrgoods[lowestsell]--; traded[lowestsell]++; comp_wantamount[lowestsell]++;
                           playsound(SND_TIMETICK,22050); // todo: vaihda sample

                           camount[lowestsell]++;
                           
                           landgrand_count -= 3;
                           play_tradesound();
                           notmoved = 0;
                           aucts.storeamount++;
                           plr_money[lowestsell] += price[lowestsell];
                           changed |= 2;

                           if (aucts.plrgoods[lowestsell] == 0)
                             {  price[lowestsell] = ytoprice(62);
                                strcpy (auctmessage,"SELLER RAN OUT OF GOODS");
                                comp_wants[lowestsell] = 0;
                                auctmessagetime = 100;
                             }
                           else
                             if (aucts.plrgoods[lowestsell] == aucts.plrneed[lowestsell])
                               {  price[lowestsell] = ytoprice(62);
                                  strcpy (auctmessage,"SELLER AT CRITICAL LEVEL");
                                  comp_wants[lowestsell] = 0;
                                  auctmessagetime = 100;
                               }
                        }
                   }
                 if (!z) sellcounter = -1;
              } // else { z=0 ...

            landgrand_accelerate = notmoved; // if no-one moves, accelerate time


          } // if !counter

        if ( (auctmessagetime == 0) && (auctmessage[0] != 0) )
          {  auctmessage[0] = 0;
             changed |= 2;
          }

        if (changed)
          {  for (i = 0; i < 4; i++)
               ypos[i] = pricetoy(price[i]);
             if ( (changed & 4) && (shopbuys) )
               {  shopbuys = 0;
                  bbar (34,148,34+30,148+27);
               }
             if (changed & 2)
               {  movememo(66,20, 200,179, backg, ruutu);

                  if (auctmessagetime)
                    writemid (160,189,auctmessage);
               
                  for (z=0,i=0; i < 4; i++)
                    if ( (sellbuy[i] == A_BUY) && (price[i] > z) ) z = price[i];
                  if (z < aucts.storebuyprice)
                    {  if (shopbuys)
                         {  putnpic (80,162,buyline);
                            itoa (aucts.storebuyprice, rivi, 10);
                            writemid (255, 162-4, rivi);
                         }
                    }
                  else
                    {  itoa (z,rivi,10);
                       putnpic (80,pricetoy(z)-1,buyline); // shop
                       writemid (255, pricetoy(z)-4, rivi);
                    }


                  for (z=90000,i=0; i < 4; i++)
                    if ( (sellbuy[i] == A_SELL) && (price[i] < z) ) z = price[i];
                  if (z > aucts.storesellprice) // shop!
                    {  if (aucts.storeamount) // if there is something in shop
                         {  putnpic (81,66,sellline);
                            itoa (aucts.storesellprice, rivi, 10);
                            writemid (80, 66-4, rivi);
                         }
                    }
                  else
                    {  putnpic (81,pricetoy(z)-1,sellline);
                       itoa (z,rivi,10);
                       writemid (81, pricetoy(z)-4, rivi);
                    }

                  writef (30,30,"CREDITS:",1);
                  writef (30,178,"TRADED:",1);
                  for (i = 0; i < 4; i++)
                    {  if (plrrace[i] == 8)
                         putpiccolorize (85+i*45,ypos[i]-23,racesprites[(int)plrrace[i]][(int)((rand()%3)*4+sellbuy[i])],colortable2[i+1] );
                       else
                         putpiccolorize (85+i*45,ypos[i]-23,racesprites[(int)plrrace[i]][(int)(get_step2(&step[i])+sellbuy[i])],colortable2[i+1] );

                       itoa (plr_money[i],rivi,10);
                       writemid (97+i*45,30, rivi);
                       itoa (traded[i],rivi,10);
                       writemid (97+i*45,178, rivi);
                    }
                  changed |= 1;
               }
             if (changed & 1) flip();
             changed = 0;
          }
//        if (keybuffer[1]) break;

        check_shutdown();
        if (exitgame) return;
     }

   timetick_speed = -1;

   playwithdelay (SND_BELL,22050,20);
   playwithdelay (SND_BELL,22050,20);
   playwithdelay (SND_BELL,22050,20);
     
   landgrand_accelerate = 0; // if no-one moves, accelerate time

   timer_routine = NULL;
}

// each plot in use needs an unit of food
// check!! mapowner == 1--4 ???
void calc_foodneed (int* need0, int plr)
{  int o,need;
   need = 0;
   for (o = 0; o < 81; o++)
     if ( (mapowner[o] == plr+1) && (mapprod[o]) )
       need++;
   *need0 = need;
}

// calculate food production for player
int calc_foodprod (int plr)
{  int o, prod;
   prod = 0;
   for (o = 0; o < 81; o++)
     if ( (mapowner[o] == plr+1) && (mapprod[o] == R_FOOD+1) )
       {  //prod += mapknownprod[R_FOOD+1][o] / 10;
          prod += planetres[R_FOOD+1][o] / 10; // computer cheats here...
       }
   return prod;
}

// each non-energyproducing plot in use needs an unit of energy
// check!! mapowner == 1--4 ???
void calc_energyneed (int* need0, int plr)
{  int o,need;
   need = 0;
   for (o = 0; o < 81; o++)
     if ( (mapowner[o] == plr+1) && (mapprod[o]) )
       need++;
   *need0 = need;
}


// calculate energy production for player
int calc_energyprod (int plr)
{  int o, prod;
   prod = 0;
   for (o = 0; o < 81; o++)
     if ( (mapowner[o] == plr+1) && (mapprod[o] == R_ENERGY+1) )
       {  //prod += mapknownprod[R_FOOD+1][o] / 10;
          prod += planetres[R_ENERGY+1][o] / 10; // computer cheats here...
       }
   return prod;
}

void goods_auction()
{  int i,p;
   auctiontype auct;

   if (exitgame) return;

// NEW AUCTION CODE;
//  new auction is otherwise complete, only computer AI is missing;
//  you need to write it before new auction system can be used

/*
   auct.aucttype = AUCT_FOOD;
//   auct.landseller = -1;
   auct.amount[0] = 40;
   auct.amount[1] = 28;
   auct.amount[2] =  6;
   auct.amount[3] =  2;

   auct.consumption[0] =  4;
   auct.consumption[1] =  4;
   auct.consumption[2] =  4;
   auct.consumption[3] =  4;

   auct.production[0] =  1;
   auct.production[1] =  2;
   auct.production[2] =  3;
   auct.production[3] =  4;

   auct.spoilage[0] =  4;
   auct.spoilage[1] =  3;
   auct.spoilage[2] =  2;
   auct.spoilage[3] =  1;

   auct.needlevel[0] =  3;
   auct.needlevel[1] =  3;
   auct.needlevel[2] =  3;
   auct.needlevel[3] =  3;

   auct.shopamount = 5;
   auct.shopbuyprice = 10;
   auct.shopsellprice = 30;

   show_new_auction ( &auct );

   return;
*/


// remaining of these use old auction system; system was
// ineffective and computer AI sucked. new system however
// is not implemented completely, so old system is in use
   // ------------ore------------------
   memset (&aucts, 0, sizeof(aucts) );

   // no usage
   // no need
   // amount
   for (i = 0; i < 4; i++) aucts.plrgoods[i] = plr_ore[i];
   // production
   for (i = 0; i < 4; i++) aucts.plrprod[i] = plr_oreprod[i];

   aucts.spoilmin = 80; // spoils if more than 80 units
   aucts.spoillevel = 0.2; // 20% spoils

   p = (int)(sin(priceangle)*30);
   aucts.storeamount = shop_ore;
   aucts.storebuyprice = shop_oreprice+p;
   aucts.storesellprice = shop_oreprice+70+p;

   show_auction ("ORE", 1); // 1=ore,25=energy,49=food,73=cryst
   for (i = 0; i < 4; i++) plr_ore[i] = aucts.plrgoods[i];
   shop_ore = aucts.storeamount;

   //----------------food------------------
   memset (&aucts, 0, sizeof(aucts) );

   // amount
   for (i = 0; i < 4; i++) aucts.plrgoods[i] = plr_food[i];
   // production
   for (i = 0; i < 4; i++) aucts.plrprod[i] = plr_foodprod[i];
   // usage
   for (i = 0; i < 4; i++) calc_foodneed ( (int*)&aucts.plrusage[i], i );
   // need
   for (i = 0; i < 4; i++)
     plr_foodneed[i] = aucts.plrneed[i] = aucts.plrusage[i];
   // no exceeds please
   for (i = 0; i < 4; i++) if (aucts.plrusage[i] > aucts.plrgoods[i]) aucts.plrusage[i] = aucts.plrgoods[i];



   aucts.spoilmin = 6; // spoils if more than 6 units
   aucts.spoillevel = 0.5; // 50% spoils

   p = (int)(sin(priceangle)*20);
   aucts.storeamount = shop_food;
   aucts.storebuyprice = shop_foodprice+p;
   aucts.storesellprice = shop_foodprice+p+40;

   if (aucts.storebuyprice < 8) aucts.storebuyprice = 8;

   show_auction ("FOOD", 49); // 1=ore,25=energy,49=food,73=cryst
   for (i = 0; i < 4; i++) plr_food[i] = aucts.plrgoods[i];
   shop_food = aucts.storeamount;

   //----------------energy------------------
   memset (&aucts, 0, sizeof(aucts) );

   // amount
   for (i = 0; i < 4; i++) aucts.plrgoods[i] = plr_energy[i];
   // production
   for (i = 0; i < 4; i++) aucts.plrprod[i] = plr_energyprod[i];
   // usage
   for (i = 0; i < 4; i++) calc_energyneed ( (int*)&aucts.plrusage[i], i );
   // need
   for (i = 0; i < 4; i++)
     plr_energyneed[i] = aucts.plrneed[i] = aucts.plrusage[i];
   // no exceeds please
   for (i = 0; i < 4; i++) if (aucts.plrusage[i] > aucts.plrgoods[i]) aucts.plrusage[i] = aucts.plrgoods[i];

   aucts.spoilmin = 10; // spoils if more than 6 units
   aucts.spoillevel = 0.34; // third spoils

   p = (int)(sin(priceangle)*20);
   aucts.storeamount = shop_energy;
   aucts.storebuyprice = shop_energyprice+p;
   aucts.storesellprice = shop_energyprice+p+40;
   if (aucts.storebuyprice < 8) aucts.storebuyprice = 8;

   show_auction ("ENERGY", 25); // 1=ore,25=energy,49=food,73=cryst
   for (i = 0; i < 4; i++) plr_energy[i] = aucts.plrgoods[i];
   shop_energy = aucts.storeamount;

   //---------------------cristite--------------------------
   memset (&aucts, 0, sizeof(aucts) );

   // amount
   for (i = 0; i < 4; i++) aucts.plrgoods[i] = plr_crystal[i];
   // production
   for (i = 0; i < 4; i++) aucts.plrprod[i] = plr_crystalprod[i];
   // no usage
   // no need
   // no exceeds please

   aucts.spoilmin = 80; // spoils if more than 6 units
   aucts.spoillevel = 0.2; // 20% spoils

   p = (int)(sin(priceangle)*45);
   aucts.storeamount = 0; // store never has cristite
   aucts.storebuyprice = shop_crystalprice+p;
   aucts.storesellprice = shop_crystalprice+p+70;

   show_auction ("CRISTITE", 73); // 1=ore,25=energy,49=food,73=cryst
   for (i = 0; i < 4; i++) plr_crystal[i] = aucts.plrgoods[i];
   shop_crist += aucts.storeamount;

}

// meteor hits square
void meteor_at_square( int o )
{  int xp,yp, xi,yi, c, x,y;
   writemid (160,90,"Meteor has hit the planet");
   memmove (backg, ruutu, 64000);

   xp = ((o%9)*22 + 23-12)*16;
   yp = ((o/9)*22 + 12-23)*16;

   yi = 28;
   xi = -5;

   yp -= (yi*100);
   xp -= (xi*100);

   c = 0;
   while (yp < -640)
     {  xp += xi;
        yp += yi;
        c++;
        check_shutdown();
        if (exitgame) return;
     }

   for (; c < 100; )
     {  if (landgrand_count)
          {  landgrand_count = 0;
             x = (xp >> 4) - 2; y = (yp >> 4) - 2;
             if (x < 12) x = 12;
             if (y < 1) y = 1;
             if (x > 209-30) x = 209-30;
             if (y > 199-30) x = 199-30;
             movememo (x,y, 30,30, backg, ruutu);
             putanimpic (xp>>4, yp>>4, animspr[ANM_METEOR][c % 3]);
             flip();
             xp += xi;
             yp += yi;
             c++;
          }
        check_shutdown();
        if (exitgame) return;
     }

   planetres[R_CRYSTAL][o] = 40; // VERY HIGH cristite
   mapprod[o] = 0; // mule is destroyed
   draw_map();
   draw_mapprod();
   show_prodmapfast();

   memmove (backg,ruutu, 64000);
   xp = ((o%9)*22 + 23-11);
   yp = ((o/9)*22 + 12-11);
   counter = 5;
   for (c = 0; c < 10; )
     {  if (!counter)
          {  counter = 5;
             movememo (xp,yp, 22,22, backg, ruutu);
             if (c < 9)
               putanimpic (xp, yp, animspr[ANM_METEOREXPLO][c]);
             flip();
             c++;
          }
        check_shutdown();
        if (exitgame) return;
     }
   
}

void acid_rain_storm()
{
   float xp,yp, toy, yi;
   int mx,my, x,y;

   writemid (160,90,"Acidic storm");
   writemid (160,100,"Food production up, energy down");
   memmove (backg, ruutu, 64000);

   xp = -20;
   yp = (rand() % 200);

   toy = (rand() % 200);

   yi = ((float)(toy-yp)) / 260.0;

   counter = 0;
   while (xp < 240)
     {  if (!counter)
          {  counter = 2;
             xp ++;
             yp += yi;

             mx = (((int)(xp))-12) / 9;
             my = (((int)(xp))-1) / 9;

             if ( (mx>=0) && (mx<=8) && (my>=0) && (my<=8) )
               {  mapprodscale[R_ENERGY][mx+my*9] = 0x08;
                  mapprodscale[R_FOOD][mx+my*9] = 0x18;
               }

             x = ((int)xp) - 12;
             y = ((int)yp) - 22;

             if (x < 12) x = 12;
             if (y < 1) y = 1;
             if (x > 209-30) x = 209-30;
             if (y > 199-30) x = 199-30;
             x = ((int)xp) - 12;
             y = ((int)yp) - 22;
             movememo (x,y, 30,30, backg, ruutu);
             putanimpic (x, y, animspr[ANM_STORM][rand() % 3]);
             if ((rand() % 20) == 0)
               putanimpic (x, y, animspr[ANM_STORM][3+rand() % 2]);
             flip();
          }
        check_shutdown();
        if (exitgame) return;
     }


   flip();
   
}

// find total production of one good
int find_productions (int what)
{  int o,p;
   for (p=o=0; o < 81; o++)
     if ( (mapprod[o] == what) && (mapsize->allowtable[o]) )
       p += (planetres[what-1][o] / 10);
   return p;
}

// find total production of one good
int find_consumptions(int what)
{  int p,c,c2;
   c = 0;

   if (what == R_FOOD+1)
     for (p = 0; p < 4; p++)
       {  calc_foodneed ( &c2, p);
          c += c2;
       }

   if (what == R_ENERGY+1)
     for (p = 0; p < 4; p++)
       {  calc_energyneed ( &c2, p);
          c += p;
       }
     
   return c;
}

void check_shopprices()
{
   int avail,need,da,dp;
   int dprice,prod,cons;

/*   oldf = shop_foodprice;
   olde = shop_energyprice;
   oldc = shop_crystalprice;
   oldo = shop_oreprice; */

   if (exitgame) return;

   shop_food -= (rand() % 5);
   shop_energy -= (rand() % 5);
   shop_ore -= (rand() % 2); shop_ore -= 1;
   shop_crist = 0;

   if ( (shop_ore > 50) && (rand() % 2) ) shop_ore /= 2;
   if ( (shop_food > 40) && (rand() % 2) ) shop_food /= 2;
   if ( (shop_energy > 40) && (rand() % 2) ) shop_energy /= 2;

/*   c = shop_energy; if (c < 0) c = 0;
   shop_energyprice = (int) ( 130/sqrt(  (float)(c)/2+1 ) ); // energy;
//   c = shop_food; if (c < 0) c = 0;
//   shop_foodprice = (int) ( 110/sqrt(  (float)(c)/2+1 ) ); // food;
   c = shop_ore; if (c < 0) c = 0;
   shop_oreprice = (int) ( 170/sqrt(  (float)(c)/4+1 ) ); // ore;
//   c = shop_crist; if (c < 0) c = 0;
//   shop_crystalprice = (int) (400/sqrt(  ((float)(c))*1.2+4 ) ); // crist
   shop_oreprice += (10-shop_mules) * 6; */

/*
//   if (oldf <= 0) shop_foodprice += (rand() % 10)+5;
   if (olde <= 0) shop_energyprice += (rand() % 15)+5;
   if (oldo <= 0) shop_oreprice += (rand() % 20)+5;
//   if (oldc <= 0) shop_crystalprice += (rand() % 35)+5;

//   if (shop_crist < 0) shop_crystalprice -= shop_crist*7;
//   if (shop_crist < 0) shop_crist = 0; */

   if (shop_energy < 0) shop_energy = 0;
   if (shop_food < 0) shop_food = 0;
   if (shop_ore < 0) shop_ore = 0;

/* // prices go up ...

   c = (rand() % 9)-4;
   if ( (oldo - shop_oreprice) > 20-c) shop_oreprice = oldo - 20 + c;
//   if ( (oldc - shop_crystalprice) > 30-c) shop_crystalprice = oldc - 30 + c;
//   if ( (oldf - shop_foodprice) > 15-c) shop_foodprice = oldf - 15 + c;
   if ( (olde - shop_energyprice) > 15-c) shop_energyprice = olde - 15 + c;

   // prices go down ...
   if ( (oldo - shop_oreprice) <-20+c) shop_oreprice = oldo + 20 - c;
//   if ( (oldc - shop_crystalprice) <-30+c) shop_crystalprice = oldc + 30 - c;
//   if ( (oldf - shop_foodprice) <-15+c) shop_foodprice = oldf + 15 - c;
   if ( (olde - shop_energyprice) <-15+c) shop_energyprice = olde + 15 - c;
*/

#ifdef DEBUG
   sprintf (rivi,"Shop stats at month %i",month);
   debuglog (rivi);
#endif

   dprice = 0;
   prod = find_productions (R_FOOD+1);
   cons = find_consumptions (R_FOOD+1);
   dprice = (-shop_food) / 10; // shop has; price reduced
   dprice += (cons-prod) / 2;
   shop_foodprice += dprice;

#ifdef DEBUG
   sprintf (rivi,"food: prod=%i, cons=%i, avail=%i, price=%i, delta=%i",
                     prod,cons,shop_food,shop_foodprice,dprice);
   debuglog (rivi);
#endif

   dprice = 0;
   prod = find_productions (R_ENERGY+1);
   cons = find_consumptions (R_ENERGY+1);
   dprice = (-shop_energy) / 10; // shop has; price reduced
   dprice += (cons-prod) / 2;
   shop_energyprice += dprice;

#ifdef DEBUG
   sprintf (rivi,"ener: prod=%i, cons=%i, avail=%i, price=%i, delta=%i",
                     prod,cons,shop_energy,shop_energyprice,dprice);
   debuglog (rivi);
#endif
   

   avail = 0;
   need = (month/3) + (rand() % 4);
   da = need-avail;
   dp = da*((rand() % 5));
   if (dp < -35) dp = -35;
   if (dp > +35) dp = +35;
   shop_crystalprice += dp;

   avail = shop_ore;
   need = (month/4) + (rand() % 4);
   need += (10-shop_mules);
   da = need-avail;
   dp = da*((rand() % 6));
   if (dp < -30) dp = -30;
   if (dp > +30) dp = +30;
   shop_oreprice += dp;

/*   avail = shop_food;
   need = (month/5) + (rand() % 3);
   da = need-avail;
   dp = da*((rand() % 6)+3);
   if (dp < -15) dp = -15;
   if (dp > +15) dp = +15;
   shop_foodprice += dp;

   avail = shop_energy;
   need = (month/5) + (rand() % 3);
   da = need-avail;
   dp = da*((rand() % 6)+3);
   if (dp < -15) dp = -15;
   if (dp > +15) dp = +15;
   shop_energyprice += dp; */

   // lower nominal with amounts
   if (shop_oreprice < 50-(shop_ore/5)) shop_oreprice = 50-(shop_ore/5);
   if (shop_crystalprice < 65-(shop_crist/5)) shop_crystalprice = 65-(shop_crist/5);
   if (shop_energyprice < 15-(shop_energy/5)) shop_energyprice = 15-(shop_energy/5);
   if (shop_foodprice < 15-(shop_food/5)) shop_foodprice = 15-(shop_food/5);

   // ABSOLUTE rock bottom!
   if (shop_oreprice < 40) shop_oreprice = 40;
   if (shop_crystalprice < 60) shop_crystalprice = 60;
   if (shop_energyprice < 8) shop_energyprice = 8;
   if (shop_foodprice < 8) shop_foodprice = 8;

   shop_goodslevel[R_FOOD] = shop_foodprice * 10 / 20; // base: 20
   shop_goodslevel[R_ENERGY] = shop_energyprice * 10 / 30; // base: 30
   shop_goodslevel[R_ORE] = shop_oreprice * 10 / 50; // base: 50
   shop_goodslevel[R_CRYSTAL] = shop_oreprice * 10 / 70; // base: 70
}


void toxic_wasteescape()
{  int xp,x,y, lmx,mx;
   memmove (backg,ruutu, 64000);

   xp = -10;
   counter = 1; lmx = -1;
   while (xp < 220)
     {  if (!counter)
          {  counter = 1;
             xp++;
             mx = (xp-18) / 22;
             if (lmx != mx)
               {  lmx = mx;
                  for (y = 0; y < 9; y++)
                    if (mapprod[mx+y*9])
                      {  if (mapowner[mx+y*9] == (leader+1))
                           {  if (!(rand() % 2))
                                {  mapprod[mx+y*9] = 0;
                                   playsound (SND_MULEDEATH,22050);
                                }
                           }
                         else
                           {  if (!(rand() % 4))
                                {  mapprod[mx+y*9] = 0;
                                   playsound (SND_MULEDEATH,22050);
                                }
                           }
                      }
                  draw_map();
                  draw_mapprod();
                  memmove (backg,ruutu, 64000);
               }
             x = xp-2; if (x < 12) x = 12;
             if (x > 209-12) x = 209-12;
             movememo (x,1,13,198, backg, ruutu);
             for (y = 0; y < 9; y++)
               putanimpic (xp+(rand() % 2),y*22+1,animspr[ANM_TOXIC][rand() % 2]);
             writemid (160,90,"Toxic waste has escaped from nearby illegal");
             writemid (160,100,"toxic dumb and is killing mules!");
             flip();

          }
        check_shutdown();
        if (exitgame) return;
     }

}

void insect_swarm()
{  int xp,x,y, lmx,mx,i;
   memmove (backg,ruutu, 64000);

   xp = -10;
   counter = 1; lmx = -1;

   zero_acks();
   for (i = 0; i < 4; i++)
     {  plr_food[i] = 0; plr_foodprod[i] = 0; }
   while (xp < 220)
     {  if (!counter)
          {  counter = 1;
             xp++;
             mx = (xp-18) / 22;
             if (lmx != mx)
               {  lmx = mx;
                  for (y = 0; y < 9; y++)
                    if (mapprod[mx+y*9] == R_FOOD+1)
                      {  prodmap3[mx+y*9] = 0;
                      }
                  draw_map();
                  draw_mapprod();
                  show_prodmapfast();
                  memmove (backg,ruutu, 64000);
               }
             x = xp-2; if (x < 12) x = 12;
             if (x > 209-12) x = 209-12;
             movememo (x,1,13,198, backg, ruutu);
             for (y = 0; y < 9; y++)
               putanimpic (xp+(rand() % 2),y*22+1,animspr[ANM_INSECTS][rand() % 2]);
             writemid (160,90,"A swarm of hungry insects have found the");
             writemid (160,100,"colony and are eating all the food!");
             flip();

          }
        check_shutdown();
        if (exitgame) return;
     }

}

void pirates_visit()
{  int xp,x,p,c,o,i,flame;
   char map1[81];

   zero_acks();
   draw_map();
   draw_mapprod();
   show_prodmapfast();
   memmove (backg,ruutu, 64000);
   
   xp = 215;
   counter = 2;
   flame = nopiratetime = 0;
   while (xp > 84)
     {  if (!counter)
          {  xp--;
             x = xp-2;
             if (x < 12) x = 12;
             if (x > 209-56) x = 209-56;
             movememo (x,84,70,32, backg, ruutu);
             putanimpic (xp,84, animspr[ANM_PIRATES][0]);
             putanimpic (xp+50,84+6, animspr[ANM_PIRATEFLAME][flame / 4]);
             putanimpic (xp+50,84+17, animspr[ANM_PIRATEFLAME][flame / 4]);
             flame++; if (flame > 7) flame = 0;
             writemid (160,90,"PIRATES!");
             counter = 2;
             flip();
          }
        check_shutdown();

        if (exitgame) break;
     }

   p = 0; counter = 5;
   while (p < 7)
     {  if (!counter)
          {  p++;
             movememo (84,84,76,32, backg, ruutu);
             putanimpic (84,84, animspr[ANM_PIRATES][p]);
             writemid (160,90,"PIRATES!");
             counter = 5;
             flip();
          }
        check_shutdown();

        if (exitgame) break;
     }


   c = 0;
   for (i = 0; i < 4; i++)
     {  plr_crystal[i] = 0; plr_crystalprod[i] = 0;  }
   memset (map1, 0, 9*9);
   for (o = 0; o < 81; o++)
     {  if (mapprod[o] == R_CRYSTAL+1)
          { c++; map1[o] = 1;  }
     }
     
   counter = 5;
   while (c > 0)
     {  if (!counter)
          {  counter = 5;
             o = -1;
             while (o == -1)
               {  o = rand() % 81;
                  if ( (map1[o] == 0) || (mapsize->allowtable[o] == 0) ) o = -1;
                  check_shutdown();
                  if (exitgame) return;
               }

             map1[o] = 0;
             if (mapprod[o] == R_CRYSTAL+1)
               prodmap3[o] = 0;

             draw_map();
             draw_mapprod();
             putanimpic (84,84, animspr[ANM_PIRATES][p]);
             show_prodmapfast();
             writemid (160,90,"PIRATES!");
             writemid (160,100,"Pirates take all cristite!");
             flip();
             c--;
          }
        check_shutdown();
        if (exitgame) return;
     }

   draw_map();
   draw_mapprod();
   show_prodmapfast();
   movememo (84,84,56,32, ruutu,backg);

   counter = 5;
   while (p > 0)
     {  if (!counter)
          {  p--;
             movememo (84,84,56,32, backg, ruutu);
             putanimpic (84,84, animspr[ANM_PIRATES][p]);
             writemid (160,90,"PIRATES!");
             writemid (160,100,"Pirates take all cristite!");
             flip();
             counter = 5;
          }
        check_shutdown();
        if (exitgame) return;
     }

   while (xp > -45)
     {  if (!counter)
          {  xp--;
             x = xp-2;
             if (x < 12) x = 12;
             if (x > 209-56) x = 209-56;
             movememo (x,84,70,32, backg, ruutu);
             putanimpic (xp,84, animspr[ANM_PIRATES][0]);
             putanimpic (xp+50,84+6, animspr[ANM_PIRATEFLAME][flame / 4]);
             putanimpic (xp+50,84+17, animspr[ANM_PIRATEFLAME][flame / 4]);
             flame++; if (flame > 7) flame = 0;
             writemid (160,90,"PIRATES!");
             writemid (160,100,"Pirates take all cristite!");
             flip();
             counter = 2;
          }
        check_shutdown();
        if (exitgame) return;
     }
}

#define ORESNATCHER_COUNT 24
void oresnatcher_visit()
{  int ypos[40],i,y,xp,mx,lmx,x;
   int phase[40],xpos[40];
   y = 3;
   nooreeatertime = 0;
   for (i = 0; i < ORESNATCHER_COUNT; i++)
     { ypos[i] = y;
       y += 7+(rand() % 3);
       xpos[i] = rand() % 7;
       phase[i] = rand() % 4;
     }

   memmove (backg,ruutu, 64000);

   /* no ore produced or in stock */
   for (i = 0; i < 4; i++)
     {  plr_ore[i] = 0; plr_oreprod[i] = 0; }

   zero_acks();

   xp = -10;
   counter = 1; lmx = -1;
   while (xp < 220)
     {  if (!counter)
          {  counter = 3;
             xp++;
             mx = (xp-14) / 22;
             if (lmx != mx)
               {  lmx = mx;
                  for (y = 0; y < 9; y++)
                    if (mapprod[mx+y*9] == R_ORE+1)
                      {  prodmap3[mx+y*9] = 0;
                      }
                  draw_map();
                  draw_mapprod();
                  show_prodmapfast();
                  memmove (backg,ruutu, 64000);
               }

               
             x = xp-2; if (x < 12) x = 12;
             if (x > 209-12) x = 209-12;
             movememo (x,1,13,198, backg, ruutu);
             for (i = 0; i < ORESNATCHER_COUNT; i++)
               {  phase[i]++;
                  if (phase[i] > 7) phase[i] = 0;
                  putanimpic (xp+xpos[i],ypos[i],animspr[ANM_ORESNATCHER][phase[i]]);
               }
             writemid (160,90,"Invastion of ore snatchers!");
             writemid (160,100,"They eat all ore!");
             flip();

          }
        check_shutdown();
        if (exitgame) break;
     }

}

// handle random event that is to happen AFTER players' activities,
// like pirates etc
void afterturn_random_event()
{  int wait;
   if (exitgame) return;
   if (afterturnevent == -1) return; // no event
   timer_routine = landgrand_timerrout;
   switch (afterturnevent)
     {  // 10 : pirates!-----------------------------------------
        case 10 : pirates_visit();
                  wait = 1;
                  break;
        // 11 : ore snatchers!--------------------------------
        case 11 : oresnatcher_visit();
                  wait = 1;
                  break;
        // 11 : insect swarm!--------------------------------
        case 12 : insect_swarm();
                  wait = 1;
                  break;
     }
   if (wait) delayi (idelaytime);
}

// handle random events
// most events handled here; some are delayed until after the
// production phase
void random_event()
{  int e ,phase, o,i,c,y,o2, wait;

//   if (month == 1) return; // first turn, no event

   if (exitgame) return;
   zero_acks();

   wait = 0;

   afterturnevent = -1;
     
   purakuva ("mapgrid.dat", backg);
   memmove (mapbackg,backg,64000);
   set_gridpal (0);
   memmove (ruutu, backg, 64000);

   draw_map();
   draw_mapprod();

   timer_routine = landgrand_timerrout;

   e = rand() % 13;
   landgrand_count = 64;
   switch (e)
     {  // 00 : solar activity increase------------------------------
        case 0 :
                 phase = 0;
                 writemid (160,90,"Solar activity has increased");
                 writemid (160,100,"Energy production is doubled");
                 memset (mapprodscale[R_ENERGY], 0x20, 81);
                 flip();
                 while (1)
                   {  while ( (inportb(0x3da) & 8) != 8) ;
                      if (phase == 0)
                        {  if (landgrand_count <= 128)
                             setpale (landgrand_count,landgrand_count,landgrand_count);
                           else
                             {  phase = 1; landgrand_count = 0;  }
                        }

                      if (phase == 1)
                        {  if (landgrand_count > 30)
                             {  phase = 2; counter = 128;  }
                        }
                      if (phase == 2)
                        {  if (counter >= 64)
                             setpale (counter,counter,counter);
                           else
                             break;
                        }
                      while ( (inportb(0x3da) & 8) == 8) ;
                      check_shutdown();
                      if (exitgame) return;
                      wait = 1;
                   }
                 break;
        // 01 : solar depletion --------------------------------
        case 1 : phase = 0;
                 writemid (160,90,"Solar activity has decreased");
                 writemid (160,100,"Energy production is halved");
                 memset (mapprodscale[R_ENERGY], 0x08, 81);
                 flip();
                 counter = 64;
                 while (1)
                   {  while ( (inportb(0x3da) & 8) != 8) ;
                      if (phase == 0)
                        {  if (counter >= 32)
                             setpale (counter,counter,counter);
                           else
                             {  phase = 1; landgrand_count = 0;  }
                        }

                      if (phase == 1)
                        {  if (landgrand_count > 30)
                             {  phase = 2; landgrand_count = 32;  }
                        }
                      if (phase == 2)
                        {  if (landgrand_count <= 64)
                             setpale (landgrand_count,landgrand_count,landgrand_count);
                           else
                             break;
                        }
                      while ( (inportb(0x3da) & 8) == 8) ;
                      check_shutdown();
                      if (exitgame) return;
                      wait = 1;
                   }
                 break;
        // 02 : meteor--------------------------------
        case 2 : do { o = rand() % 81;
                      if (mapsize->allowtable[o] == 0) o = 4*9+4;
                    } while (o == 4*9+4); // NOT THE CITY!!!

                 meteor_at_square( o ); wait = 1;
                 break;

        // 03 : rainstorm-----------------------------
        case 3 : acid_rain_storm(); wait = 1;
                 break;

        // 04 : taxation-----------------------------
        case 4 : writemid (160,90,"Wealth tax");
                 writemid (160,100,"All pay 20% of current wealth");
                 flip();
                 for (i = 0; i < 4; i++)
                   plr_money[i] -= (plr_money[i] / 5);
                 wait = 1;  
                 break;

        // 05 : shop burndown --------------------------------
        case 5 : writemid (105,70,"Shop burns down");
                 landgrand_count = 0; c = 0;
                 memmove (backg, ruutu, 64000);
                 while (1)
                   {  if (landgrand_count > 150) break;
                      if (!counter)
                        {  counter = 4;
                           movememo (100,89,22,22, backg, ruutu);
                           if (landgrand_count < 145)
                             putnpic (100-4+6,89-12+13,animspr[ANM_FIRE][c]);
                           c++; if (c > 2) c = 0;
                           flip();
                        }
                      check_shutdown();
                      if (exitgame) return;
                   }
                 shop_ore = 0;
                 shop_food = 0;
                 shop_energy = 0;
                 shop_mules -= 7;
                 if (shop_mules <= 0) shop_mules = 0;
                 wait = 1;
                 break;

        // 06 : dry season--------------------------------
        case 6 : writemid (160,90,"Dry season");
                 writemid (160,100,"Food production down");
                 memset (mapprodscale[R_FOOD], 0x08, 81);
                 flip(); wait = 1;
                 break;

        // 07 : planetquake-------------------------------
        case 7 : memmove (backg,ruutu, 64000);
                 landgrand_count = 0; counter = 0;
                 playsound (SND_PLANETQUAKE,22050);
                 while (1)
                   {  if (!counter)
                        {  counter = 5;
                           o = (rand() % 6) -2;

                           if (landgrand_count > 140)
                             o = 0;
                           o = 332+o;
                           o2 = 332;

                           for (y = 1; y < 199; y++)
                             {  memmove (ruutu+o2, backg+o, 22*9);
                                o2 += 320;
                                o += 320;
                             }

                           writemid (160,90,"Planetquake!");
                           writemid (160,100,"Mining production halved");
                           flip();
                        }
                      if (landgrand_count > 150)
                        break;
                      check_shutdown();
                      if (exitgame) return;
                   }
                 
                 wait = 1;
                 break;
        // 08 : shift in core-------------------------------
        case 8 : memmove (backg,ruutu, 64000);
                 writemid (160,90,"A sudden shift deep in planet's core has moved");
                 writemid (160,100,"all cristite concentrations in new locations.");

                 memset (mapknowncrist,-1, 81); // known kristite layer; not known
                 memset (mapknownprod[R_CRYSTAL],0, 81); // known kristite layer; not known

                 memset (planetres[R_CRYSTAL], 0, 81);
                 for (i = 0; i < 4; i++) // add 3 cristite fields
                   add_cristitefield();
                                  
                 flip();
                 wait = 1;
                 break;

        // 09 : toxic fumes-------------------------------
        case 9 : toxic_wasteescape();
                 wait = 1;
                 break;

        // 10 : pirates!-----------------------------------------
        case 10: afterturnevent = 10;
                 break;
        // 11 : ore snatchers!-----------------------------------
        case 11: afterturnevent = 11;
                 break;
        // 12 : insect swarm!-----------------------------------
        case 12: afterturnevent = 12;
                 break;

     }

   if (wait) delayi (idelaytime);
}


void init_month()
{  int d;
   memset (mapprodscale, 0x10, 81*4);

   if (exitgame) return;

   d = 1+rand() % 2; // produce mules; each takes 2 ore
   if (shop_mules < 0) shop_mules = 0;
   if (shop_mules + d > 10) d = 10-shop_mules;
   if (d*2 > shop_ore) d = shop_ore / 2;
   shop_mules += d; // 1 or 2 mules per turn
   shop_ore -= d*2;
   if (shop_mules > 10) shop_mules = 10;

   switch (shop_mules+(rand() % 3))
     {  case 0  : muleprice = 999; break;
        case 1  : muleprice = 240; break;
        case 2  : muleprice = 220; break;
        case 3  : muleprice = 200; break;
        case 4  : muleprice = 180; break;
        case 5  : muleprice = 160; break;
        case 6  : muleprice = 140; break;
        case 7  : muleprice = 120; break;
        case 8  : muleprice = 110; break;
        case 9  : muleprice = 105; break;
        case 10 : muleprice = 100; break;
        case 11 : muleprice =  95; break;
        case 12 : muleprice =  90; break;
        case 13 : muleprice =  80; break;
     }

   month++;

   if (landauct_startprice > 10)
     landauct_startprice -= ( rand() % (landauct_startprice / 10) );
   else
     landauct_startprice = (rand() % 30) + 10;

   priceangle += (3.14159* ( (float) ( 3+(rand()%4) ) ) / ((float)(game_length)) ); // 2-3 cycles in 12 months, approx

   nopiratetime++;
   nooreeatertime++;
}


void flash_mappiece(int o)
{  int i;
   for (i = 0; i < idelaytime/(7); i++)
     {  draw_map();
        draw_mapprod();
        if (i & 1)
          putnpic ( 12+(o % 9)*22, 1+(o / 9)*22, selsprites[0]);
        flip();
        if (delayap (10)) break;
        if (exitgame) break;
     }
}

int find_player_mules(int plr, int prod)
{  int i,c;
   if (prod)
     {  for (c=0,i=0; i < 81; i++) // specific prod
          if ( (mapowner[i]==plr+1) && (mapprod[i] == prod+1) ) c++;
     }
   else
     {  for (c=0,i=0; i < 81; i++) // any prod
          if ( (mapowner[i]==plr+1) && (mapprod[i]) ) c++;
     }
   return c;
}

int pick_grandland()
{  int o,c;
   c = 0;
   while (c < 300)
     {  o = rand() % 81;
        if ((mapsize->allowtable[o]) && (mapowner[o] == 0)) return o;
        c++;
     }
   return -1;
}

int pick_loseland(int plr)
{  int o,c;
   c = 0;
   while (c < 300)
     {  o = rand() % 81;
        if (mapowner[o] == (plr+1)) return o;
        c++;
     }
   return -1;
}

int find_muleplot(int plr)
{  int o,c;
   c = 0;
   while (c < 300)
     {  o = rand() % 81;
        if ( (mapowner[o] == (plr+1)) && (mapprod[o]) ) return o;
        c++;
     }
   return -1;
}

int find_nomuleplot(int plr)
{  int o,c;
   c = 0;
   while (c < 300)
     {  o = rand() % 81;
        if ( (mapowner[o] == (plr+1)) && (!mapprod[o]) ) return o;
        c++;
     }
   return -1;
}

// player random events
void check_player_random_event(int plr)
{  int badgood,i,o,o2,c, wait;
   badgood = (rand() % 150);
   if (leader == plr) badgood += 40;
   wait = 0;
   zero_acks();

   reset_keys();

   if (badgood < 40)
     {  // good news
        i = rand() % 8;
        switch (i)
          {  case  0 : // landgrand
                       o = pick_grandland(); wait = 1;
                       if (o != -1) // not found
                         {  playsound (SND_GOODNEWS,22050);
                            for (i = 0; i < idelaytime/(7); i++)
                              {  draw_map();
                                 draw_mapprod();
                                 if (i & 1)
                                   putnpic ( 12+(o % 9)*22, 1+(o / 9)*22, selsprites[0]);
                                 writemid (160,100,"You have been granted a piece of land");  
                                 flip();
                                 if (delayap (10)) break;
                                 if (exitgame) break;
                               }
                            mapowner[o] = plr+1;
                         }
                       break;
             case  1 : // supporter gives money
                       writemid (160,90,"A generous supporter has given you");
                       o = ((rand() % 5)+1) * 50;
                       sprintf (rivi, "%i credits to aid you in your cause.", o);
                       writemid (160,100,rivi);
                       plr_money[plr] += o;
                       playsound (SND_GOODNEWS,22050);
                       flip();
                       delayap(idelaytime); wait = 1;
                       break;
             case  2 : // mule won a competition
                       o = ((rand() % 5)+1) * 50; wait = 1;
                       switch (rand() % 15)
                         {  case 0 : strcpy (rivi2,"beauty"); break;
                            case 1 : strcpy (rivi2,"running"); break;
                            case 2 : strcpy (rivi2,"standing"); break;
                            case 3 : strcpy (rivi2,"laziness"); break;
                            case 4 : strcpy (rivi2,"weightlifting"); break;
                            case 5 : strcpy (rivi2,"rolling"); break;
                            case 6 : strcpy (rivi2,"dumbness"); break;
                            case 7 : strcpy (rivi2,"wisdom"); break;
                            case 8 : strcpy (rivi2,"sleeping"); break;
                            case 9 : strcpy (rivi2,"chess"); break;
                            case 10: strcpy (rivi2,"go"); break;
                            case 11: strcpy (rivi2,"mah-jong"); break;
                            case 12: strcpy (rivi2,"Quake"); break;
                            case 13: strcpy (rivi2,"modem throwing"); break;
                            case 14: strcpy (rivi2,"hacking"); break;
                         }
                       if (find_player_mules(plr,0))
                         sprintf (rivi,"Your mule has won a %s contest,",rivi2);
                       else
                         sprintf (rivi,"You have won a laziness contest,");
                       writemid (160,90,rivi);
                       sprintf (rivi,"with grand prize of %i credits.",o);
                       playsound (SND_GOODNEWS,22050);
                       writemid (160,100,rivi);
                       plr_money[plr] += o;
                       flip();
                       delayap(idelaytime);
                       break;
             case  3 : // relative died, leaving money
                       o = ((rand() % 5)+1) * 50; wait = 1;
                       writemid (160,90,"A distant relative of yours has died, leaving you");
                       writemid (160,100,"enormous amount of money. However, after lawyers'");
                       sprintf (rivi,"fees only %i credits is left.", o);
                       playsound (SND_GOODNEWS,22050);
                       writemid (160,110,rivi);
                       plr_money[plr] += o;
                       flip();
                       delayap(idelaytime);
                       break;
             case  4 : // sold c64 game to an collector
                       wait = 1;
                       writemid (160,90,"You have sold your old C-64 game named MULE");
                       writemid (160,100,"to an collector and gained 100 credits");
                       plr_money[plr] += 100;
                       playsound (SND_GOODNEWS,22050);
                       flip();
                       delayap(idelaytime);
                       break;
             case  5 : // won billgates shooting competition
                       wait = 1;
                       writemid (160,90,"You won a local contests called 'shoot most Bill");
                       writemid (160,100,"Gateses to save the universe', with grand prize");
                       writemid (160,110,"of 100 credits and newest version of Linux");
                       plr_money[plr] += 100;
                       playsound (SND_GOODNEWS,22050);
                       flip();
                       delayap(idelaytime);
                       break;
             case  6 : // plots changed
                       o = pick_loseland(plr); wait = 1;
                       o2 = pick_grandland();
                       if ((o != -1) && (o2 != -1)) // not found
                         {  mapowner[o] = 0;
                            mapowner[o2] = plr+1;
                            playsound (SND_GOODNEWS,22050);  
                            for (i = 0; i < idelaytime/(7); i++)
                              {  draw_map();
                                 draw_mapprod();
                                 if (i & 1) putnpic ( 12+(o % 9)*22, 1+(o / 9)*22, selsprites[0]);
                                 if (!(i & 1)) putnpic ( 12+(o2 % 9)*22, 1+(o2 / 9)*22, selsprites[0]);
                                 writemid (160,100,"Confusion in claim office has changed your claim");
                                 flip();
                                 if (delayap (10)) break;
                                 if (exitgame) break;
                               }
                         }
                       break;
             case  7 : // folks back home help a bit
                       wait = 1;
                       writemid (160,90,"You have received an aid package from home");
                       writemid (160,100,"with 2 food and 2 energy in it.");
                       playsound (SND_GOODNEWS,22050);
                       plr_food[plr] += 2;
                       plr_energy[plr] += 2;
                       flip();
                       delayap(idelaytime);
                       break;
          } // switch
     } // if badgood<30
     
   if (badgood > 110)
     {  // BAAD news
        i = rand() % 8;
        switch (i)
          {  case  0 : // solar collectors dirty, clean
                       c = find_player_mules(plr,R_ENERGY);
                       if (c)
                         {  o = 150*c;
                            if (plr_money[plr] >= o)
                              {  plr_money[plr] -= o;
                                 writemid (160,90,"Your mules' solar collectors are dirty.");
                                 sprintf (rivi,"Cleaning them costs $150 each, totalling $%i.",o);
                                 writemid (160,100,rivi);
                                 flip();
                                 playsound (SND_BADNEWS,22050);  
                                 delayap(idelaytime); wait = 1;
                              }
                         }
                       break;
             case  1 : // digging parts worn out, repair
                       c = find_player_mules(plr,R_ORE);
                       if (c)
                         {  o = 200*c;
                            if (plr_money[plr] >= o)
                              {  plr_money[plr] -= o;
                                 writemid (160,90,"Your mules' mining equipment have worn out.");
                                 sprintf (rivi,"Replacing them costs $200 each, totalling $%i.",o);
                                 writemid (160,100,rivi);
                                 flip();
                                 playsound (SND_BADNEWS,22050);  
                                 delayap(idelaytime); wait = 1;
                              }
                         }
                       break;
             case  2 : // relative died, left money
                       o = ((rand() % 5)+1) * 50;
                       if (plr_money[plr] >= o)
                         {  writemid (160,80,"A distant relative of yours has died, leaving you");
                            writemid (160,90,"enormous amount of money. However, after lawyers'");
                            sprintf (rivi,"fees nothing is left, and you actually have to pay %i", o);
                            writemid (160,100,rivi);
                            writemid (160,110,"credits to afford to pay to the lawyers.");
                            plr_money[plr] -= o;
                            flip();
                            playsound (SND_BADNEWS,22050);
                            delayap(idelaytime); wait = 1;
                         }
                       break;
             case  3 : // microsoft fees
                       if (plr_money[plr] >= 100)
                         {  writemid (160,90,"Microsoft(r) requires you to pay your weekly licences");
                            writemid (160,100,"for using their software which cost you 100 credits");
                            plr_money[plr] -= 100;
                            flip();
                            playsound (SND_BADNEWS,22050);
                            delayap(idelaytime); wait = 1;
                         }
                       break;
             case  4 : // microsoft fees
                       if (plr_money[plr] >= 100)
                         {  writemid (160,90,"Your house's roof has collapsed.");
                            writemid (160,100,"Repairs cost you 100 credits.");
                            plr_money[plr] -= 100;
                            flip();
                            playsound (SND_BADNEWS,22050);
                            delayap(idelaytime); wait = 1;
                         }
                       break;
             case  5 : // lose a plot!
                       o = pick_loseland(plr); wait = 1;
                       if (o != -1) // not found
                         {  mapowner[o] = 0;
                            playsound (SND_BADNEWS,22050);
                            for (i = 0; i < idelaytime/(7); i++)
                              {  draw_map();
                                 draw_mapprod();
                                 if (i & 1)
                                   putnpic ( 12+(o % 9)*22, 1+(o / 9)*22, selsprites[0]);
                                 writemid (160,100,"Your claim to land has been expired");
                                 flip();
                                 if (delayap (10)) break;
                                 if (exitgame) break;
                               }
                         }
                       break;
             case  6 : // plots changed
                       o = pick_loseland(plr); wait = 1;
                       o2 = pick_grandland();
                       if ((o != -1) && (o2 != -1)) // not found
                         {  mapowner[o] = 0;
                            mapowner[o2] = plr+1;
                            playsound (SND_BADNEWS,22050);
                            for (i = 0; i < idelaytime/(7); i++)
                              {  draw_map();
                                 draw_mapprod();
                                 if (i & 1) putnpic ( 12+(o % 9)*22, 1+(o / 9)*22, selsprites[0]);
                                 if (!(i & 1)) putnpic ( 12+(o2 % 9)*22, 1+(o2 / 9)*22, selsprites[0]);
                                 writemid (160,100,"Confusion in claim office has changed your claim");
                                 flip();
                                 if (delayap (10)) break;
                                 if (exitgame) break;
                               }
                         }
                       break;
             case  7 : // mule confused, wanders elsewhere
                       o = find_muleplot(plr); wait = 1;
                       o2 = find_nomuleplot(plr);
                       if ((o != -1) && (o2 != -1)) // not found
                         {  mapprod[o2] = mapprod[o];
                            mapprod[o] = 0;
                            playsound (SND_BADNEWS,22050);
                            for (i = 0; i < idelaytime/(7); i++)
                              {  draw_map();
                                 draw_mapprod();
                                 if (i & 1) putnpic ( 12+(o % 9)*22, 1+(o / 9)*22, selsprites[0]);
                                 if (!(i & 1)) putnpic ( 12+(o2 % 9)*22, 1+(o2 / 9)*22, selsprites[0]);
                                 writemid (160,100,"Mule is confused and wanders elsewhere");
                                 flip();
                                 if (delayap (10)) break;
                                 if (exitgame) break;
                               }
                         }
                       break;
          } // swich
     } // if
}

void show_shopmules()
{  int mulex[10] = {146,168,146,168,146,168,146,168,146,168};
   int muley[10] = {159,159,147,147,135,135,123,123,111,111};
   int c;

   c = shop_mules;
   if (c <= 0) return; // uh-oh
   if (c > 10) c = 10;
   while (c)
     {  putnpic (mulex[c-1],muley[c-1], shopmulepic);
        c--;
     }
   
}



int find_nonmodmap(int plr, int prod)
{  int o;
   for (o = 0; o < 81; o++)
     if ( (mapowner[o]==plr+1) && (!mapmodfd[o]) && (mapprod[o] != prod+1) )
       {  if ( (prod == R_ORE) && (mapprod[o] == R_CRYSTAL+1) && (mapknownprod[R_CRYSTAL][o] > 1) )
            { // no way, cristite being produced here
            }
          else
            return (o);
       }
   return (-1);
}

// find a place for a energy plant
int pick_energyplace(int plr)
{  int o,max,maxo,s;

   // first try to find an empty plot
   max = -5; maxo = -1;
   for (o = 0; o < 81; o++)
     {  if ( (mapowner[o] == plr+1) && (mapprod[o] == 0) && (!mapmodfd[o]) )
          {  s = -5;
             if (planetmap[1][o] == 1) s = 7; // hills
             if (planetmap[1][o] == 2) s = 5; // med mnt
             if (planetmap[1][o] == 3) s = 3; // high mnt
             if (planetmap[1][o] == 0) s = 10; // plains
             if (planetmap[1][o] >= 13 && planetmap[1][o] <= 39) s = 9; // river
             s += (get_neighbors2 (o, R_ENERGY+1, plr+1) / 2);

             if (s > max)
               { maxo = o; max = s; }
          }
     }
   if (max > 0) return maxo; // found empty plot!

   max = -5; maxo = -1;
   for (o = 0; o < 81; o++)
     {  if ( (mapprod[o] != R_ENERGY) && (mapowner[o] == plr+1) && (!mapmodfd[o]) ) // no empty, find an used one
          {  s = -5;
             if (planetmap[1][o] == 1) s = 7; // hills
             if (planetmap[1][o] == 2) s = 5; // med mnt
             if (planetmap[1][o] == 3) s = 3; // high mnt
             if (planetmap[1][o] == 0) s = 10; // plains
             if (planetmap[1][o] >= 13 && planetmap[1][o] <= 39) s = 9; // river
             s += (get_neighbors2 (o, R_ENERGY+1, plr+1) / 2);

             if (s > max)
               { maxo = o; max = s; }
          }
     }
   return maxo;
}

// find a place for a ore mining plant
int pick_oreplace(int plr)
{  int o,max,maxo,s;

   // first try to find an empty plot
   max = -5; maxo = -1;
   for (o = 0; o < 81; o++)
     {  if ( (mapowner[o] == plr+1) && (mapprod[o] == 0) && (!mapmodfd[o]) )
          {  s = -5;
             if (planetmap[1][o] == 1) s = 5; // hills
             if (planetmap[1][o] == 2) s = 7; // med mnt
             if (planetmap[1][o] == 3) s = 10; // high mnt
             if (planetmap[1][o] == 0) s = 1; // plains
             if (planetmap[1][o] >= 13 && planetmap[1][o] <= 39) s = 1; // river
             s += (get_neighbors2 (o, R_ORE+1, plr+1) / 2);

             if (s > max)
               { maxo = o; max = s; }
          }
     }
   if (max > 0) return maxo; // found empty plot!

   max = -5; maxo = -1;
   for (o = 0; o < 81; o++)
     {  if ( (mapprod[o] != R_ORE) && (mapowner[o] == plr+1) && (!mapmodfd[o]) ) // no empty, find an used one
          {  s = -5;
             if (planetmap[1][o] == 1) s = 5; // hills
             if (planetmap[1][o] == 2) s = 7; // med mnt
             if (planetmap[1][o] == 3) s = 10; // high mnt
             if (planetmap[1][o] == 0) s = 1; // plains
             if (planetmap[1][o] >= 13 && planetmap[1][o] <= 39) s = 1; // river
             s += (get_neighbors2 (o, R_ORE+1, plr+1) / 2);

             if (s > max)
               { maxo = o; max = s; }
          }
     }
   return maxo;
}


// find a place for a food plant / food_plot find_food_p
int pick_foodplace(int plr)
{  int o,max,maxo,s;

   // first try to find an empty plot
   max = -5; maxo = -1;
   for (o = 0; o < 81; o++)
     {  if ( (mapowner[o] == plr+1) && (mapprod[o] == 0) && (!mapmodfd[o]) )
          {  s = -5;
             if (planetmap[1][o] == 1) s = 7; // hills
             if (planetmap[1][o] == 2) s = 5; // med mnt
             if (planetmap[1][o] == 3) s = 3; // high mnt
             if (planetmap[1][o] == 0) s = 8; // plains
             if (planetmap[1][o] >= 13 && planetmap[1][o] <= 39) s = 10; // river
             s += (get_neighbors2 (o, R_FOOD+1, plr+1) / 2);

             if (s > max)
               { maxo = o; max = s; }
          }
     }
   if (max > 0) return maxo; // found empty plot!

   max = -5; maxo = -1;
   for (o = 0; o < 81; o++)
     {  if ( (mapprod[o] != R_FOOD) && (mapowner[o] == plr+1) && (!mapmodfd[o]) ) // no empty, find an used one
          {  s = -5;
             if (planetmap[1][o] == 1) s = 7; // hills
             if (planetmap[1][o] == 2) s = 5; // med mnt
             if (planetmap[1][o] == 3) s = 3; // high mnt
             if (planetmap[1][o] == 0) s = 8; // plains
             if (planetmap[1][o] >= 13 && planetmap[1][o] <= 39) s = 10; // river
             s += (get_neighbors2 (o, R_FOOD+1, plr+1) / 2);

             if (s > max)
               { maxo = o; max = s; }
          }
     }
   return maxo;
}

int getttime (int x1,int y1, int x2,int y2)
{  return 10+(int)(sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ))*4;
}

// returns 1 if player has no cristite plot
int nocristiteplot(int plr)
{  int o;
   for (o = 0; o < 81; o++)
     if ( (mapowner[o]==plr+1) && (!mapmodfd[o]) &&
          (mapknowncrist[o] > 0) /*&& (mapprod[o] != prod+1)*/ )
       return (o);
   return (-1);
}

void setknowncrist (int o, int lev)
{  int x,y;
   x = o % 9;
   y = o / 9;
   mapknowncrist[o] = lev;
   lev--;
     // around; 1 less, approx
   if ((x > 0) && (mapknowncrist[o-1] < lev)) mapknowncrist[o-1] = lev;
   if ((x < 8) && (mapknowncrist[o+1] < lev)) mapknowncrist[o+1] = lev;
   if ((y > 0) && (mapknowncrist[o-9] < lev)) mapknowncrist[o-9] = lev;
   if ((y < 8) && (mapknowncrist[o+9] < lev)) mapknowncrist[o+9] = lev;
}

int find_notassayed(int plr)
{  int o,c;
   c = 0; o = -1;
   while ( (c < 100) && (o == -1) )
     {  o = rand() % 81;
        if (mapsize->allowtable[o] == 0)
          o = -1;
        else
          if ( ((mapowner[o]!=plr+1) && (rand() % 2 != 0)) || (mapknowncrist[o] != -1) )
            o = -1;
        c++;
     }
   return (o);
}

int find_optimize_ore (int plr, int *o1, int *o2 )
{  int o,max,maxo, maxori;
   for ( (*o1)++; *o1 < 81; (*o1)++)
     if ( (mapowner[*o1] == plr+1) &&
          (mapprod[*o1] == R_ORE+1) &&
          (planetres[R_ORE][*o1] < 20) ) // poor ore prod
            {  max = 0; maxo = 0;
               // found square with bad ore;
               // check what it could be good at

               // find square producing energy that could produce ore good
               max = 20; maxori = 20;
               for (o = 0; o < 81; o++)
                 {  if ( (mapowner[o] == plr+1) &&
                         (mapprod[o] == R_ENERGY+1) &&
                         (mapknownprod[R_ENERGY][o] < max) &&
                         (planetres[R_ORE][o] > 20) )
                      {  maxo = o; max = mapknownprod[R_ENERGY][o]; }
                 }
                 
               if (max < 20) // found bad food prod; set to change it
                 {  *o2 = maxo;
                    return (0); // found optimization;
                 }

               // find square producing food that could produce ore good
               max = 20; maxori = 20;
               for (o = 0; o < 81; o++)
                 {  if ( (mapowner[o] == plr+1) &&
                         (mapprod[o] == R_FOOD+1) &&
                         (mapknownprod[R_FOOD][o] < max) &&
                         (planetres[R_ORE][o] > 20) )
                      {  maxo = o; max = mapknownprod[R_FOOD][o]; }
                 }
                 
               if (max < 20) // found bad food prod; set to change it
                 {  *o2 = maxo;
                    return (0); // found optimization;
                 }
            }
   return (-1);
}

int find_optimize_crist (int plr, int *o1, int *o2 )
{  int o,max,maxo, maxori;
   for ( (*o1)++; *o1 < 81; (*o1)++)
     if ( (mapowner[*o1] == plr+1) &&
          (mapprod[*o1] == R_CRYSTAL+1) &&
          (planetres[R_CRYSTAL][*o1] < 10) ) // no crist prod
            {  max = 0; maxo = 0;
               // found square with bad crist;
               // check what it could be good at

               // find square producing energy that could produce crist good
               max = 20; maxori = 20;
               for (o = 0; o < 81; o++)
                 {  if ( (mapowner[o] == plr+1) &&
                         (mapprod[o] == R_ENERGY+1) &&
                         (mapknownprod[R_ENERGY][o] < max) &&
                         (planetres[R_CRYSTAL][o] > 20) )
                      {  maxo = o; max = mapknownprod[R_ENERGY][o]; }
                 }
                 
               if (max < 20) // found bad food prod; set to change it
                 {  *o2 = maxo;
                    return (0); // found optimization;
                 }

               // find square producing food that could produce ore good
               max = 20; maxori = 20;
               for (o = 0; o < 81; o++)
                 {  if ( (mapowner[o] == plr+1) &&
                         (mapprod[o] == R_FOOD+1) &&
                         (mapknownprod[R_FOOD][o] < max) &&
                         (planetres[R_CRYSTAL][o] > 20) )
                      {  maxo = o; max = mapknownprod[R_FOOD][o]; }
                 }
                 
               if (max < 20) // found bad food prod; set to change it
                 {  *o2 = maxo;
                    return (0); // found optimization;
                 }
            }
   return (-1);
}

// --------------------------------------------------------------

// computer activities
#define ACT_BAR 1                  // go to bar
#define ACT_SETFOOD 2              // get, train and deliver food mule
#define ACT_SETENERGY 3            // same for energy
#define ACT_SETORE 4               // same for ore
#define ACT_SETCRISTITE 5          // same for cristitite
#define ACT_BUYMULE 6              // get mule from shop
#define ACT_TRAINMULE 7            // train; targ = trainto (1=food etc)
//#define ACT_TRAINFOOD 8            // train mule for food
//#define ACT_TRAINENERGY 9          // train mule for energy
//#define ACT_TRAINORE 10            // train mule for ore
//#define ACT_TRAINCRISTITE 11       // train mule for ore
#define ACT_DELIVERMULE 12         // deliver mule; targ= square
#define ACT_ASSAY 13               // assay land; targ=sqr
#define ACT_GOTO 14                // goto; target = square
#define ACT_PRODTOFOOD 16          // refit sq mule to food; targ=square
#define ACT_PRODTOENERGY 17        // refit sq mule to energy; targ=square
#define ACT_PRODTOORE 18           // refit sq mule to ore; targ=square
#define ACT_PRODTOCRISTITE 19      // refit sq mule to crist; targ=square
#define ACT_GETMULE 20             // get mule; targ=src square

#define COMP_MAX_OPTIONS 9*9*4+256
int comp_option_count;
float comp_optionscore[COMP_MAX_OPTIONS]; // option scores
char optiontarget[COMP_MAX_OPTIONS]; // option actions
char optiontype[COMP_MAX_OPTIONS]; // what to do

void add_to_options (float score, int target, int action)
{
   if (comp_option_count >= COMP_MAX_OPTIONS)
     {  debuglog ("CompOptions: Overflow");
        return; // too many options
     }

   if (score <= 0) return; // no point
   comp_optionscore[comp_option_count] = score;
   optiontarget[comp_option_count] = target;
   optiontype[comp_option_count] = action;
     
   comp_option_count++;
}

float resetscore()
{  return ((float)( (rand() % 5) -2 )) / 5;
}

/* computer: score activity options available
   scoring: points: theoretically -inf .. +inf,
                    in practice -10 .. 10, where 10 is best option
                      available
*/
// consider_options ; consider_activities
// plr=0..3
void score_activities(int plr, int timeleft, int xp, int yp)
{  int i,o,c, need,need0,prod;
   int shortage;

   float score;

   comp_option_count = 0;

   // note: computer cheats here;
   //       it picks from actual product map instead of using "known" 
   //       prods or estimating unknown land production value

   /* first score different production options */
   /* options for empty squares */

   // score food for empty squares:
   // affecting factors: possible shortage, considering stock (major)
   //                    other players' production (minor)
   //                    land estimated production (fairly major)
   prod = calc_foodprod (plr);
   calc_foodneed ( &need0, plr);
   for (o = 0; o < 81; o++)
     if ( (mapsize->allowtable[o]) && (mapowner[o] == plr+1) && (mapprod[o] == 0) )
        // mapsize allowes; square owned; no prod
       {  score = resetscore ();

            // shortage; need-prod; <=0 -> no need
          need = need0-prod - (plr_food[plr] / 2);

            // high need scores high; 0.5 points for each food required
          score += need / 2;

          score += (planetres[R_FOOD][o]/10); // also good prod is needed...

          score += 0.7;

          add_to_options (score, o, ACT_SETFOOD);
       }

   // score energy for empty squares:
   // affecting factors: possible shortage, considering stock (major)
   //                    other players' production (minor)
   //                    land estimated production (fairly major)
   prod = calc_energyprod (plr);
   calc_energyneed ( &need0, plr);
   for (o = 0; o < 81; o++)
     if ( (mapsize->allowtable[o]) && (mapowner[o] == plr+1) && (mapprod[o] == 0) )
        // mapsize allowes; square owned; no prod
       {  score = resetscore ();

            // shortage; need-prod; less than 0 -> no need
          need = need0-prod  - (plr_energy[plr] / 2);

            // high need scores high; 0.5 points for each energy required
          score += need / 2;

          score += (planetres[R_ENERGY][o]/10); // also good prod is needed...

          add_to_options (score, o, ACT_SETENERGY);
       }

   // next, production of ore.
   // affecting factors: others' production
   for (o = 0; o < 81; o++)
     if ( (mapsize->allowtable[o]) && (mapowner[o] == plr+1) && (mapprod[o] == 0) )
        // mapsize allowes; square owned; no prod
       {  score = resetscore ();

            // if produced much, it's not wise to produce more
//          score -= (find_productions(R_ORE+1) / 40);

          score += (planetres[R_ORE][o]/7); // also good prod is needed...

          add_to_options (score, o, ACT_SETORE);
       }

   // next, production of cristite.
   // affecting factors: others' production
   for (o = 0; o < 81; o++)
     if ( (mapsize->allowtable[o]) && (mapowner[o] == plr+1) && (mapprod[o] == 0) )
        // mapsize allowes; square owned; no prod
       {  score = resetscore ();

            // if produced much, it's not wise to produce more
//          score -= (find_productions(R_CRYSTAL+1) / 40);

          score += (int)(mapknowncrist[o]*1.6); // good prod is needed...

          add_to_options (score, o, ACT_SETCRISTITE);
       }

   // refit energy productions to ore or crist:
   prod = calc_foodprod (plr);
   calc_foodneed ( &need0, plr);
   shortage = prod-need0;
   
   prod = calc_energyprod (plr);
   calc_energyneed ( &need0, plr);
   if (prod-need > 5)
     for (o = 0; o < 81; o++)
       if ( (mapowner[o] == plr+1) && (mapprod[i] == R_ENERGY+1) )
         {  if ( planetres[R_ORE+1][o] >= 30)
              {
                 score = resetscore ();
                 i = (planetres[R_ENERGY+1][o] / 10) -1;
                 score += ((planetres[R_ORE+1][o]-30) / 3) - i;
                 add_to_options (score, o, ACT_PRODTOORE);
              }
              
            if ( planetres[R_CRYSTAL+1][o] >= 20)
              {
                 score = resetscore ();
                 i = (planetres[R_ENERGY+1][o] / 10) -1;
                 score += ((planetres[R_CRYSTAL+1][o]-20) / 2) - i;
                 add_to_options (score, o, ACT_PRODTOCRISTITE);
              }

              // refit to foot - only in dire straits!
            if ( shortage < -4)
              {
                 score = resetscore ();
                 score += (planetres[R_FOOD+1][o] / 10)+2;
                 score -= (planetres[R_ENERGY+1][o] / 10);
                 add_to_options (score, o, ACT_PRODTOFOOD);
              }
         }

   // refit food productions to ore or crist or energy:
   prod = calc_energyprod (plr);
   calc_energyneed ( &need0, plr);
   shortage = prod-need0;
   
   prod = calc_foodprod (plr);
   calc_foodneed ( &need0, plr);
   if (prod-need > 5)
     for (o = 0; o < 81; o++)
       if ( (mapowner[o] == plr+1) && (mapprod[i] == R_FOOD+1) )
         {    // refit to ore
            if ( planetres[R_ORE+1][o] >= 30)
              {
                 score = resetscore ();
                 i = (planetres[R_FOOD+1][o] / 10) -1;
                 score += ((planetres[R_ORE+1][o]-30) / 3) - i;
                 add_to_options (score, o, ACT_PRODTOORE);
              }

              // refit to crystal?
            if ( planetres[R_CRYSTAL+1][o] >= 20)
              {
                 score = resetscore ();
                 i = (planetres[R_FOOD+1][o] / 10) -1;
                 score += ((planetres[R_CRYSTAL+1][o]-20) / 2) - i;
                 add_to_options (score, o, ACT_PRODTOCRISTITE);
              }

              // refit to energy - only in dire straits!
            if ( shortage < -4)
              {
                 score = resetscore ();
                 score += (planetres[R_ENERGY+1][o] / 10)+2;
                 score -= (planetres[R_FOOD+1][o] / 10);
                 add_to_options (score, o, ACT_PRODTOENERGY);
              }
         }

   for (i = 0; i < 4; i++)
     {  c = 0;
        while (c < 100)
          {  o = rand() % 81;
             if ( ((mapowner[o] == 0) || (mapowner[o] == plr+1)) && (mapsize->allowtable[o]) && (mapknowncrist[o] == -1) )
               c = 200;
             c++;
          }
        if (c >= 200)
          {  score = ((float)(rand() % 50)) / 50;
             add_to_options (score, o, ACT_ASSAY);
          }
     }
}

typedef struct { int action; // which action
                 int acttarget; // target; square, train, whatever
               } c_action_type;

c_action_type caction[8];
int cactlen ;

// store one phase of action
void storephase(int act, int targ)
{  caction[cactlen].action = act;
   caction[cactlen].acttarget = targ;
   cactlen++;
}

// set full length action
void setaction(int actnro)
{  int act,targ;

   cactlen = 0;

   if (actnro < 0)
     {  storephase( ACT_BAR,-1);
        return; // whoops
     }

   act = optiontype[actnro];
   targ = optiontarget[actnro];
   switch (optiontype[actnro])
     {
       case ACT_SETFOOD:
          storephase (ACT_BUYMULE, -1);
          storephase (ACT_TRAINMULE, R_FOOD+1);
          storephase (ACT_DELIVERMULE, targ);
          break;

       case ACT_SETENERGY:
          storephase (ACT_BUYMULE, -1);
          storephase (ACT_TRAINMULE, R_ENERGY+1);
          storephase (ACT_DELIVERMULE, targ);
          break;

       case ACT_SETORE:
          storephase (ACT_BUYMULE, -1);
          storephase (ACT_TRAINMULE, R_ORE+1);
          storephase (ACT_DELIVERMULE, targ);
          break;

       case ACT_SETCRISTITE:
          storephase (ACT_BUYMULE, -1);
          storephase (ACT_TRAINMULE, R_CRYSTAL+1);
          storephase (ACT_DELIVERMULE, targ);
          break;

       case ACT_ASSAY:
          storephase (ACT_ASSAY, targ);
          break;

       case ACT_PRODTOORE:
          storephase (ACT_GETMULE, targ);
          storephase (ACT_TRAINMULE, R_ORE+1);
          storephase (ACT_DELIVERMULE, targ);
          break;

       case ACT_PRODTOFOOD:
          storephase (ACT_GETMULE, targ);
          storephase (ACT_TRAINMULE, R_FOOD+1);
          storephase (ACT_DELIVERMULE, targ);
          break;

       case ACT_PRODTOENERGY:
          storephase (ACT_GETMULE, targ);
          storephase (ACT_TRAINMULE, R_ENERGY+1);
          storephase (ACT_DELIVERMULE, targ);
          break;

       case ACT_PRODTOCRISTITE:
          storephase (ACT_GETMULE, targ);
          storephase (ACT_TRAINMULE, R_CRYSTAL+1);
          storephase (ACT_DELIVERMULE, targ);
          break;

       default:
          storephase (act,targ);
          break;
     }
}

int pick_action()
{  int i,nro;
   float highscore;

   highscore = -100;
   nro = -1; // no action; also defaults for "go to bar"

     // go through options and pick highest ranking
   for (i = 0; i < comp_option_count; i++)
     {  if (comp_optionscore[i] >= highscore)
          {  highscore = comp_optionscore[i];
             nro = i;
          }
     }

     // no suitable options; go to bar
   if ( (nro < 0) || (comp_option_count <= 0) || (highscore <= 0) )
     {  setaction (-1); // bar; no sq needed
        return ACT_BAR;
     }

   comp_optionscore[nro] = -100; // don't redo this
   setaction (nro);
   return optiontype[nro];
}

int calc_traveltime (int compat, int target)
{  int x,y,range;
   x = ((compat % 9)*22) - ((target % 9)*22);
   y = ((compat / 9)*22) - ((target / 9)*22);

   range = (int) ( sqrt(x*x + y*y) );
   range *= (3); // timed range to location

   return range;
}

#define CA_ENERGY 1
#define CA_FOOD 2
#define CA_ORE 3
#define CA_CRIST 4
#define CA_BAR 5
#define CA_ASSAY 6
#define CA_GETMULE 7
#define CA_TRAINMULE 8
#define CA_OPTIMIZE 9
// computer activities
void computer_activities(int plr)
{  int turntime,race,color,time,o,i, breakturn, o2,timeneed;
   int endturn;

   int comp_action[10], comp_actto[10];
   int ac, act,act2, x,y, range;
   
   int forceact, forcetarget; // force computer to do something
   int target,action; // action and where/what to do

   int mulewith,mulefit;

   int actphase;
   int compat; // computer position

   if (exitgame) return;
   
   memset (mapmodfd, 0, 9*9);

   memset (ruutu,0,64000); flip();

   purakuva ("city.dat", city);
   purakuva ("mapgrid.dat", backg);
   memmove (mapbackg,backg,64000);
   set_gridpal (colortable[plr+1]);
   spritedest = city;
   getpic (222,120, 238,130, shopmulepic);
   spritedest = ruutu;
   memmove (ruutu, backg, 64000);

   writef (220,10,"Computer",1);
   zero_acks();

   timer_routine = NULL;

   time = turntime = (race_turntime[(int)plrrace[plr]]  * mapsize->timemultiplier);

   race = plrrace[plr];
   color = colortable2[plr+1];

   zero_acks();
/*   draw_map();
   draw_mapprod(); */

   reset_keys();

   draw_map();
   draw_mapprod();
   check_player_random_event(plr);

   memmove (ruutu, backg, 64000);
   draw_map();
   draw_mapprod();
   
   writef (220,10,"Computer",1);

   // food shortage: time = max-350*shortage, min=200
   if (plr_food[plr] < plr_foodneed[plr])
     {  time -= (plr_foodneed[plr]-plr_food[plr]) * 350;
        if (time < 200) time = 200;

        bbar (220,30,319,100);
        writef (220,30,"Food shortage",1);
        writef (220,40,"reduces time",1);
        flip();
        delayap (idelaytime);
     }

   compat = 4+4*9; // start at city

   actphase= 0; cactlen = 0;

   mulewith = mulefit = 0;

   endturn = 0; forceact = 0;
   while ( (time > 0) && (!endturn) )
     {  if (actphase >= cactlen) // act done
          {  score_activities(plr, time, compat%9,compat/9);
             pick_action();

             actphase = 0; // start from beginning
          }

          // get target for action (sq or whatever)
        target = caction[actphase].acttarget;
        action = caction[actphase].action;

/*        memmove (ruutu,backg,320*10);
        sprintf (rivi,"%i %i %i",target,action, forceact);
        writef (1,1,rivi,1);
        flip();

        if (keybuffer[2])
          while (!keybuffer[2]) ;*/

        if (keybuffer[3])
          keybuffer[3] = 0;

        if (forceact) // forced action
          {  action = forceact;
             target= forcetarget;
             forceact = 0;
          }

        if (action) // if action defined
          switch (action)
            {  case ACT_GOTO : // ---go to location-------------
                       range = calc_traveltime (compat,target);


                       if (range >= time) // not enough time
                         {  forceact = ACT_BAR; // simply to bar
                         }
                       else // enough time; go for it
                         {  time -= range;
                            compat = target;
                         }
                       break; // act_goto
                       
               case ACT_BAR : // ----BAR----------------------------
                       // todo: timecheck

                       // mule taken; sell it first
                       if (mulewith)
                         plr_money[plr] += muleprice;

                       do { o = rand() % (40+(month*15));
                            if (leader == plr)
                              o -= (rand() % 80);
                            o -= rand() % 40;
                          } while (abs(o) < 10);

                       if (o < 0)
                         {  if ((plr_money[plr]+o) < 0) o = -plr_money[plr];
                            sprintf (rivi,"Computer lost %i by gambling", -o);
                            msgwindow (rivi,"","");
                         }
                       else
                         {  sprintf (rivi,"Computer won %i by gambling", o);
                            msgwindow (rivi,"","");
                         }
                       plr_money[plr] += o;
                     
                       delayap (idelaytime);

                       time = 1;
                       endturn = 1;
                       break; // act_bar

               case ACT_BUYMULE :
                       if (compat != 4+4*9) // not in city
                         {  forcetarget = 4+4*9;
                            forceact = ACT_GOTO;
                         }
                       else // in city, ok to buy mule
                         {  if (plr_money[plr] < muleprice+100)
                              forceact = ACT_BAR; // not enough money for buying and training
                            else
                              {  mulewith = 1; mulefit = 0; // get mule
                                 plr_money[plr] -= muleprice;
                                 time -= 20;
                                 actphase++;
                              }
                         }
                       break; // act_buymule

               case ACT_TRAINMULE:
                       if (compat != 4+4*9) // city?
                         {  forcetarget = 4+4*9;
                            forceact = ACT_GOTO;
                         }
                       else
                         {  if (plr_money[plr] < muletraincost[target])
                              forceact = ACT_BAR; // no money; go to bar
                            else
                              {  plr_money[plr] -= muletraincost[target];
                                 mulefit = target; // 1=food, 2=energ, 3=ore, 4=crist
                                 actphase++;
                                 time -= 100;
                              }
                         }
                       break;

               case ACT_GETMULE:
                       if (compat != target)
                         {  forcetarget = target;
                            forceact = ACT_GOTO;
                         }
                       else
                         {  panic (mapprod[target]==0,"Getting nonexistent mule");
                            mulefit = mapprod[target];
                            mulewith = 1;

                            mapprod[target] = 0;
                         }
                       break;

               case ACT_DELIVERMULE:
                       if (compat != target)
                         {  forcetarget = target;
                            forceact = ACT_GOTO;
                         }
                       else
                         {  panic (mulewith==0,"Delivering nonexistent mule");
                            panic (mulefit==0,"Delivering unfit mule");

                            o = mapprod[compat];
                            mapprod[compat] = mulefit;

                             // check if mule replaced
                            if (o) // replace; take other mule with
                              {  mulefit = o; mulewith = 1;
                              }
                            else // no previous mule
                              {  mulewith = mulefit = 0; }

                            draw_map();
                            draw_mapprod();
                            flash_mappiece (compat);
                            draw_map();
                            draw_mapprod();
                            time -= 20;
                            
                            actphase++;
                         }
               
                       break;

               case ACT_ASSAY :
                         // time to go to city and from assay to plot and back
                       range = calc_traveltime (compat, 4+4*9) +
                               calc_traveltime (4+4*9, target)*2 + 100;


                       if (time >= range)
                         {  compat = 4+4*9;
                            time -= range;

                            i = (planetres[R_CRYSTAL][target] / 10)+1;
                            setknowncrist (target, i-1);

                            bbar (220,30,319,100);
                            switch (i)
                              {  case 1 : writef (220,30,"No cristite",1); break;
                                 case 2 : writef (220,30,"Low cristite",1); break;
                                 case 3 : writef (220,30,"Medium cristite",1); break;
                                 case 4 : writef (220,30,"High cristite",1); break;
                                 case 5 : writef (220,30,"Very high cristite",1); break;
                              }

                            draw_map();
                            draw_mapprod();
                            flash_mappiece (target);
                            actphase++;
                         }
                       else
                         {  forceact = ACT_BAR;
                         }
                       break;

                 // inform of weird habits computer may have
               default :
                       sprintf (rivi, "Unexpected idea: %i", action);
                       panic (1,rivi);
                       break;
            } // if cactlen ... switch caction

#ifdef DEBUG
        if (keybuffer[88]) break;
#endif
     }

   if (time <= 0)
     {  bbar (220,30,319,100);
        writef (220,30,"Computer ran",1);
        writef (220,40,"out of time",1);
        playwithdelay (SND_BELL,22050,20);
        flip();
        delayap (idelaytime);
     }

/*
   // although there is check if prod is known, it always should be in
   // this point...! (as it has produced...)
   // analyze food need
   calc_foodneed ( &need, plr); //need -= rand() % 5;
   provide = 0;
//   if (plr_food[plr] > need) need -= plr_food[plr]-need;
   for (o = 0; o < 81; o++)
     if ( (mapowner[o] == plr+1) && (mapprod[o] == R_FOOD+1) )
       if (mapknownprod[R_FOOD][o] > 10)
         provide += (mapknownprod[R_FOOD][o] /10); // known, pessimistic estimate
       else
         provide += 3;
         
   if (provide < need) // not enough food
     {  for (o = 0; o < 81; o++)
          if ( (mapowner[o] == plr+1) && (mapprod[o] == R_FOOD+1) )
            mapmodfd[o]++; // don't touch!
        needfood = (need-provide+2) / 3; // at least 1 new
     }
   else
     {  i = (need+2) / 3;
        for (o = 0; o < 81; o++)
          if ( (mapowner[o] == plr+1) && (mapprod[o] == R_FOOD+1) )
            {  mapmodfd[o]++; // don't touch!
               i--; if (i < 1) break; // allow change
            }
        needfood = 0;
     }

   // although there is check if prod is known, it always should be in
   // this point...! (as it has produced...)
   // analyze energy need
   calc_energyneed ( &need, plr); //need -= rand() % 5;
   provide = 0;
//   if (plr_energy[plr] > need) need -= plr_energy[plr]-need;
   for (o = 0; o < 81; o++)
     if ( (mapowner[o] == plr+1) && (mapprod[o] == R_ENERGY+1) )
       if (mapknownprod[R_ENERGY][o]>10)
         provide += (mapknownprod[R_ENERGY][o]/10); // known, pessimistic estimate
       else
         provide += 3;
         
   if (provide < need) // not enough food
     {  for (o = 0; o < 81; o++)
          if ( (mapowner[o] == plr+1) && (mapprod[o] == R_ENERGY+1) )
            mapmodfd[o]++; // don't touch!
        needenergy = (need-provide+2) / 3; // at least 1 new
     }
   else
     {  i = (need+2) / 3;
        for (o = 0; o < 81; o++)
          if ( (mapowner[o] == plr+1) && (mapprod[o] == R_ENERGY+1) )
            {  mapmodfd[o]++; // don't touch!
               i--; if (i < 1) break; // allow change
            }
        needenergy = 0;
     }

   while (needenergy > 0)
     {  comp_action[comp_actc] = CA_ENERGY;
        comp_actto[comp_actc] = pick_energyplace(plr);
        if (comp_actto[comp_actc] != -1)
          {  mapmodfd[comp_actto[comp_actc]] = 1; comp_actc++; }
        needenergy--;
     }

   while (needfood > 0)
     {  comp_action[comp_actc] = CA_FOOD;
        comp_actto[comp_actc] = pick_foodplace(plr);
        if (comp_actto[comp_actc] != -1)
          comp_actc++;
        needfood--;
     }

   if (month == 12) // last turn; do absolutely nothing
     {  comp_actc = 1;
        comp_action[0] = CA_BAR;
     }
   
   ac = 0; breakturn = 0;
   count = 0;
   while ( (time > 0) && (!breakturn) && (!exitgame) )
     {  count ++;
        if (count > 120) break;
        check_shutdown();
        if (exitgame) return;
        incac = 0;
        if (ac < comp_actc) // preset activities
          {  if ((comp_action[ac] == CA_ENERGY) && (mulewith == 0))
                {  act = CA_GETMULE; act2 = comp_actto[ac];} // get a mule
             if ((comp_action[ac] == CA_ENERGY) && (mulewith) && (mulefit != R_ENERGY+1) )
                {  act = CA_TRAINMULE; act2 = R_ENERGY+1; } // get energy mule
             if ((comp_action[ac] == CA_ENERGY) && (mulewith) && (mulefit == R_ENERGY+1) )
                {  act = CA_ENERGY; act2 = comp_actto[ac]; incac++; } // set energy mule

             if ((comp_action[ac] == CA_FOOD) && (mulewith == 0))
                {  act = CA_GETMULE; act2 = comp_actto[ac];} // get a mule
             if ((comp_action[ac] == CA_FOOD) && (mulewith) && (mulefit != R_FOOD+1) )
                {  act = CA_TRAINMULE; act2 = R_FOOD+1; } // get energy mule
             if ((comp_action[ac] == CA_FOOD) && (mulewith) && (mulefit == R_FOOD+1) )
                {  act = CA_FOOD; act2 = comp_actto[ac]; incac++; } // set food mule

             if ((comp_action[ac] == CA_ORE) && (mulewith == 0))
                {  act = CA_GETMULE; act2 = comp_actto[ac];} // get a mule
             if ((comp_action[ac] == CA_ORE) && (mulewith) && (mulefit != R_ORE+1) )
                {  act = CA_TRAINMULE; act2 = R_ORE+1; } // get energy mule
             if ((comp_action[ac] == CA_ORE) && (mulewith) && (mulefit == R_ORE+1) )
                {  act = CA_ORE; act2 = comp_actto[ac]; incac++; } // set ore mule

             if ((comp_action[ac] == CA_CRIST) && (mulewith == 0))
                {  act = CA_GETMULE; act2 = comp_actto[ac];} // get a mule
             if ((comp_action[ac] == CA_CRIST) && (mulewith) && (mulefit != R_CRYSTAL+1) )
                {  act = CA_TRAINMULE; act2 = R_CRYSTAL+1; } // get cristite mule
             if ((comp_action[ac] == CA_CRIST) && (mulewith) && (mulefit == R_CRYSTAL+1) )
                {  act = CA_CRIST; act2 = comp_actto[ac]; incac++; } // set cristite mule

             if ( (act == CA_GETMULE) && (shop_mules <= 0) )
               {  act = CA_ASSAY; incac++; } // no damn mules

             if (comp_action[ac] == CA_BAR)
               {  act = CA_BAR; incac++; } // forced bar

             if (comp_action[ac] == CA_ASSAY)
               {  act = CA_ASSAY; incac++; } // forced assay

             if (incac) ac++;
          }
        else
          {  act = 0;
             if ( (!act) && plr_money[plr] < muleprice+100) // no money?
               act = CA_OPTIMIZE;

             if ( (comp_strategy[plr] == 0) || ( (o=nocristiteplot(plr)) == -1) )
               {  if ( (!act) && ( (o=find_nonmodmap(plr,R_ORE)) == -1) ) // no non-modified map?
                    act = CA_ASSAY;
                  if ( (!act) )
                    {  ac = 0; comp_actc = 1;
                       comp_action[0] = CA_ORE;
                       comp_actto[0] = o;
                       act = 99;
                    }
               }
             else
               {  if ( (!act) && ( o == -1 ) )
                    act = CA_BAR;
                  if ( (!act) )
                    {  ac = 0; comp_actc = 1;
                       comp_action[0] = CA_CRIST;
                       comp_actto[0] = o;
                       act = 99;
                    }
               }

             if ( (!act) ) // can't think of anything else to do!
               act = CA_OPTIMIZE;

             if (count > 50)
               act = CA_BAR; // no forever loops, no sir-e!

          }

        switch (act)
          {  case CA_OPTIMIZE  : o = 0;
                                 i = find_optimize_ore(plr, &o, &o2 );
                                 if (!i) // found, change
                                   {  timeneed = gettime (xp,yp,(o % 9)*22+15,(o / 9)*22+5) +
                                                 gettime ((o % 9)*22+15,(o / 9)*22+5,(o2 % 9)*22+15,(o2 / 9)*22+5);
                                      if (timeneed > time) // not enough time to optimize
                                        {  comp_actc = 1;
                                           comp_action[0] = CA_ASSAY;
                                           break;
                                        }

                                      time -= timeneed;

                                      mulefit = mapprod[o];
                                      mapprod[o] = 0;

                                      i = mapprod[o2];
                                      mapprod[o2] = mulefit;
                                      flash_mappiece(o2);

                                      mapprod[o] = i;
                                      flash_mappiece(o);

                                      mulefit = 0;

                                      xp = (o % 9)*22+15;
                                      yp = (o / 9)*22+5;
                                   }
                                   
                                 o = 0;
                                 i = find_optimize_crist(plr, &o, &o2 );
                                 if (!i) // found, change
                                   {  timeneed = gettime (xp,yp,(o % 9)*22+15,(o / 9)*22+5) +
                                                 gettime ((o % 9)*22+15,(o / 9)*22+5,(o2 % 9)*22+15,(o2 / 9)*22+5);
                                      if (timeneed > time) // not enough time to optimize
                                        {  comp_actc = 1;
                                           comp_action[0] = CA_ASSAY;
                                           break;
                                        }

                                      time -= timeneed;

                                      mulefit = mapprod[o];
                                      mapprod[o] = 0;

                                      i = mapprod[o2];
                                      mapprod[o2] = mulefit;
                                      flash_mappiece(o2);

                                      mapprod[o] = i;
                                      flash_mappiece(o);

                                      mulefit = 0;

                                      xp = (o % 9)*22+15;
                                      yp = (o / 9)*22+5;
                                   }
                                 break;
                                 
             case CA_ASSAY     : time -= getttime (xp,yp,4*22+15,4*22+5);
                                 if (time <= 0) break;

                                 o = find_notassayed(plr);

                                 if (o <= 0)
                                   {  count = 100;
                                   }
                                 else
                                   if ( (time - 2*(getttime (xp,yp,(o % 9)*22+15,(o / 9)*22+5)) ) > 15)
                                     {  time -= (2*(getttime (xp,yp,(o % 9)*22+15,(o / 9)*22+5))+10) ;

                                        i = (planetres[R_CRYSTAL][o] / 10)+1;
                                        setknowncrist (o, i-1);

                                        bbar (220,30,319,100);
                                        switch (i)
                                          {  case 1 : writef (220,30,"No cristite",1);
                                                      break;
                                             case 2 : writef (220,30,"Low cristite",1);
                                                      break;
                                             case 3 : writef (220,30,"Medium cristite",1);
                                                      break;
                                             case 4 : writef (220,30,"High cristite",1);
                                                      break;
                                             case 5 : writef (220,30,"Very high cristite",1);
                                                      break;
                                          }

                                        draw_map();
                                        draw_mapprod();
                                        flash_mappiece (o);
                                     }
                                 break;
                                 
             case CA_ENERGY    : time -= getttime (xp,yp,(act2 % 9)*22+15,(act2 / 9)*22+5);
                                 if (time <= 0) break;

                                 bbar (220,30,319,100);
                                 mulefit = mapprod[act2];
                                 mulewith = (mapprod[act2] != 0);
                                 mapprod[act2] = R_ENERGY+1;
                                 mapmodfd[act2] = 1;

                                 draw_map();
                                 draw_mapprod();
                                 
                                 flash_mappiece (act2);
                                 draw_map();
                                 draw_mapprod();

                                 xp = (act2 % 9)*22+15;
                                 yp = (act2 / 9)*22+5;
                                 break;

             case CA_ORE       : time -= getttime (xp,yp,(act2 % 9)*22+15,(act2 / 9)*22+5);
                                 if (time <= 0) break;

                                 bbar (220,30,319,100);
                                 mulefit = mapprod[act2];
                                 mulewith = (mapprod[act2] != 0);
                                 mapprod[act2] = R_ORE+1;
                                 mapmodfd[act2] = 1;

                                 draw_map();
                                 draw_mapprod();
                                 flash_mappiece (act2);
                                 draw_map();
                                 draw_mapprod();

                                 xp = (act2 % 9)*22+15;
                                 yp = (act2 / 9)*22+5;
                                 break;

             case CA_CRIST     : time -= getttime (xp,yp,(act2 % 9)*22+15,(act2 / 9)*22+5);
                                 if (time <= 0) break;

                                 bbar (220,30,319,100);
                                 mulefit = mapprod[act2];
                                 mulewith = (mapprod[act2] != 0);
                                 mapprod[act2] = R_CRYSTAL+1;
                                 mapmodfd[act2] = 1;

                                 draw_map();
                                 draw_mapprod();
                                 
                                 flash_mappiece (act2);
                                 draw_map();
                                 draw_mapprod();

                                 xp = (act2 % 9)*22+15;
                                 yp = (act2 / 9)*22+5;
                                 break;

             case CA_FOOD      : time -= getttime (xp,yp,(act2 % 9)*22+15,(act2 / 9)*22+5);
                                 if (time <= 0) break;

                                 bbar (220,30,319,100);
                                 mulefit = mapprod[act2];
                                 mulewith = (mapprod[act2] != 0);
                                 mapprod[act2] = R_FOOD+1;
                                 mapmodfd[act2] = 1;

                                 draw_map();
                                 draw_mapprod();
                                 
                                 flash_mappiece (act2);
                                 draw_map();
                                 draw_mapprod();

                                 xp = (act2 % 9)*22+15;
                                 yp = (act2 / 9)*22+5;
                                 break;
                                 
             case CA_GETMULE   : time -= getttime (xp,yp,4*22+11,4*22+11);
                                 if (time <= 0) break;

                                 if (time - getttime (xp,yp,(act2 % 9)*22+15,(act2 / 9)*22+5) < 20)
                                   {  mapmodfd[act2] = 1; // no time to get there
                                      ac++; // no loop
                                      break;
                                   }
                                 
                                 if (plr_money[plr] < muleprice)
                                    { ac = 0; comp_actc = 1; comp_action[0] = CA_BAR; break; } // no money, nevermind
                                 plr_money[plr] -= muleprice;
                                 mulewith = 1;
                                 shop_mules--;
                                 mulefit = 0; xp = 4*22+11; yp = 4*22+11;
                                 break;
                                 
             case CA_TRAINMULE : time -= getttime (xp,yp,4*22+11,4*22+11);
                                 if (time <= 0) break;
                                 if (plr_money[plr] < muletraincost[act2])
                                    { ac = 0; comp_actc = 1; comp_action[0] = CA_BAR; break; } // no money, nevermind
                                 plr_money[plr] -= muletraincost[act2];
                                 mulefit = act2;
                                 break;
                                 
             case CA_BAR       : time -= getttime (xp,yp,4*22+11,4*22+11);
                                 if (time <= 0) break;

                                 // return mule
                                 if (mulewith)
                                   {  time -= 40;
                                      if (time <= 0) break;
                                      plr_money[plr] += muleprice*2/3;
                                      shop_mules++;
                                      time -= 30;
                                      if (time <= 0) break;
                                   }
             
                                 do { o = rand() % (40+(month*15));
                                      if (leader == plr)
                                        o -= (rand() % 80);
                                       o -= rand() % 40;
                                     } while (abs(o) < 10);

                                 bbar (220,30,319,100);
                                 if (o < 0)
                                   {  if ((plr_money[plr]+o) < 0)
                                        o = -plr_money[plr];
                                      sprintf (rivi,"Lost %i by", -o);
                                      writef (220,30,rivi,1);
                                      writef (220,40,"gambling",1);
                                   }
                                 else
                                   {  sprintf (rivi,"Won %i by", o);
                                      writef (220,30,rivi,1);
                                      writef (220,40,"gambling",1);
                                   }
                                 plr_money[plr] += o;
                                 breakturn = CA_BAR;
                                 break;
          } // switch
        check_shutdown();
     }

   if ( (time <= 0) && (breakturn == 0) )
     {  bbar (220,30,319,100);
        writef (220,30,"Computer ran",1);
        writef (220,40,"out of time",1);
     }

   flip();

   delayap (idelaytime);  */
}

void update_mapdecors()
{  int i;
   if (!ingame) return;

   if ( (--bushupdate) <= 0)
     {  bushupdate = 10;
        for (i = 0; i < 20; i++)
          if ((rand() & 15) == 2)
            bushpic[i] = rand() % 3;
        changed |= 0x10;
     }
}

// players setting mules etc
void player_activities(int plr) // plr 0..4
{  int incity,i,b,y,x,o,xm,ym,ly;
   volatile int step,walked;
   int xp,yp,dir; // plr x/y/dir
   int mxp,myp,mdir,mstep; // mule x/y/dir
   int mtox, mfit, mfitto,mfittimer;
   int race,color,keys, turntime;
   int sampletaken,samplefrom;
   int reducetime, canact, showplr,beersample;
   char *mapspr;

   int movecounter; // slowdown counter; mounts and water
   float sabottimer;

   int wormphase, wormcount, wormx, wormy;

   int fishx,fishy,fishphase,fishcount,fishtries;
   
   int minx,miny;

   char xlotable[195], xhitable[195];

   int allworklen,allworklines,showallwork;


   if (exitgame) return;
    // create allow-movement table for city.
    // movement has three cases:
    //      y < 80: can move horizontally if xhi[x] = 1
    // 80 <=y <=86: can move horizontally ("main street")
    //      y > 86: can move horizontally if xlo[x] = 1
    // (and basically same for vertical movement (if no door in position...)
   for (x = 0; x < 193; x++)
     {  b = 1;
        if ( (x >=  0) && (x <  27) ) b = 0;
        if ( (x >  36) && (x <  71) ) b = 0;
        if ( (x >  81) && (x < 117) ) b = 0;
        if ( (x > 126) && (x < 162) ) b = 0;
        if ( (x > 171) && (x < 193) ) b = 0;
        xhitable[x] = b;

        b = 1;
        if ( (x >=  0) && (x <  29) ) b = 0;
        if ( (x >  39) && (x <  86) ) b = 0;
        if ( (x >  93) && (x < 139) ) b = 0;
        if ( (x > 166) && (x < 193) ) b = 0;
        xlotable[x] = b;
     }

   landgrand_accelerate = 0;
   purakuva ("city.dat", city);
   purakuva ("mapgrid.dat", backg);
   memmove (mapbackg,backg,64000);
   set_gridpal (colortable[plr+1]);
   spritedest = city;
   getpic (222,120, 238,130, shopmulepic);
   spritedest = ruutu;
   memmove (ruutu, backg, 64000);

   // start at mid of city
   incity = 1; xp = 98; yp = 83;
   sabottimer = 0;

   turntime = (int)(race_turntime[plrrace[plr]] * mapsize->timemultiplier);

   race = plrrace[(int)plr];
   color = colortable2[(int)plr+1];
   keys = plrcontrol[(int)plr];
   dir = 2;

   zero_acks();
   draw_map();
   draw_mapprod();
   movememo (12,1, 22*9,22*9, ruutu,backg);


   writef (220,20,"PRESS BUTTON",1);
   writef (220,30,"TO START YOUR",1);
   writef (220,40,"TURN.",1);
   setpale (64,64,64); flip();
   
   for (i = 0; i < 200; i++)
     {  draw_map();
        draw_mapprod();
        if (i & 1)
          remove_playermap (plr);
        flip();
        check_shutdown();
        if (exitgame) return;
        if (delayp(plr, 10)) break;
     }

   bbar (220,0,319,199);

   check_player_random_event(plr);

   timer_routine = landgrand_timerrout;

   counter = 2;
   muletaken = 0;
   mulerunaway = 0;
   mfit = 0;

   citymsgtime = 0;

   memmove (ruutu, backg, 64000);
   draw_map();
   draw_mapprod();

   ly = 50;
   drawcolor = 0xb6; aline (300,50,300,150);
   drawcolor = 0xb2; aline (301,50,301,150);
   drawcolor = 0xb4; aline (302,50,302,150);
   drawcolor = 0xb7; aline (303,50,303,150);
   drawcolor = 0xba; aline (304,50,304,150);

   beersample = rand();

   // food shortage:
   // time = max - 350*shortage, with minimum of 200 time
   landgrand_count = 0;
   if (plr_food[plr] < plr_foodneed[plr])
     {  landgrand_count += (plr_foodneed[plr]-plr_food[plr]) * 350;
        if (landgrand_count > (turntime-200)) landgrand_count = turntime-200;
        strcpy (citymsg, "Food shortage reduces time");
        citymsgtime = 100;
        play_errorsound();
     }
   sampletaken = 0;
   mfittimer = 0;

   reducetime = 1; canact = 1; showplr = 1;
   fishphase = wormphase = 0;
   fishtries = 1;

   changed = 0x11; // draw whole city

   //          0 : 1/3hz = 150ticks
   // "turntime" : 10hz = 5ticks
   //            --- diff = 145
   // 150 - (145 * landgrand_count / turntime);

   timetick_speed = -1;

   allworklen = 0; allworklines = 0;

   if (nobartime[plr] >= 10)
     showallwork = 1;
   else
     showallwork = 0;

   movecounter = 0;

   while (1 && !exitgame)
     {
        if (reducetime)
          {  y = 50+(landgrand_count / (turntime/100) );

             if (y != ly)
               {  drawcolor = 0; bbar (300,ly,305,y); ly = y;
                  changed++;
               }
          }
        else
          {   // counter; wait 2sec after end of turn
             if (!sellcounter)
               break;
             if (getk(plr,K_FIRE))
               sellcounter = 0;
          }

        if (landgrand_count < turntime)
          {  timetick_speed = 150- (145 * landgrand_count / turntime);
          }

        if ( (landgrand_count >= turntime) && (reducetime) )
          {  incity = 0; reducetime = 0; showplr = 0;
             changed = 1;
             canact = 0;
             sellcounter = 100; // wait 2sec
             strcpy (citymsg, "You ran out of time!");
             nobartime[plr]++;
             playwithdelay (SND_BELL,22050,20);
             timetick_speed = -1;
             citymsgtime = 100;
             if (muletaken) {  mulerunaway = 1; muletaken = 0;  }
          }
     
        if (changed)
          {  if (incity)
               {  // in the city

//                  if (changed & 0x10)
                    {  movememo (12,1, 22*9,22*9, city, ruutu); // city backg
                    }
/*                  else
                    {  movememo (12,50, 22*9,120, city, ruutu); // city backg; smaller
                    } */
                  sprintf (rivi, "$%i",muleprice);
                  writemid (164,172,rivi);

                  movememo (0,90, 12,10, backg, ruutu);
                  movememo (210,90, 89,10, backg, ruutu);

                  bbar (220,10,299,50);
                  writef (225,10,"CITY",1);


                  writef (225,25,"Credits:",1);
                  itoa (plr_money[plr],rivi,10);
                  writef (225,35,rivi,1);

                  show_shopmules();

//                  itoa (step, rivi, 10);
//                  writef (220,2, rivi,1);

                  if (muletaken)
                    putpiccolorize (mxp,myp,racesprites[0][mdir+get_step(&mstep)], color);

                  if (race == 8)
                    putpiccolorize (xp,yp, racesprites[race][dir+(rand() % 3)*4], color );
                  else
                    putpiccolorize (xp,yp, racesprites[race][dir+get_step(&step)], color );

                  movememo (0,80, 12,32, backg, ruutu);
                  movememo (210,80, 12,32, backg, ruutu);

                  if (citymsgtime)
                    if (citymsg[0]) writemid (160,90,citymsg);
               }
             else
               {  // outside the city
                  bbar (220,10,299,100);
                  if (changed & 0x10) // map changed; 0x10=redraw; 0x01=partial
                    {  draw_map();
                       movememo (12,1, 22*9,22*9, ruutu,backg);
                    }
                  else
                    movememo (12,1, 22*9,22*9, backg,ruutu);

                  movememo (0,90, 12,10, backg, ruutu);
                  movememo (210,90, 89,10, backg, ruutu);

                  if (fishphase)
                    putnpic (fishx, fishy, animspr[ANM_FISH][fishphase-1]);

                  if (wormphase)
                    putnpic (wormx, wormy, animspr[ANM_WORM][wormphase-1]);

                  draw_mapprod();

                  if (muletaken || mulerunaway)
                    putpiccolorize (mxp-4,myp-4,racesmall[0][mdir+get_step(&mstep)], color);

                  if (showplr)
                    {
                       if (race == 8)
                         putpiccolorize (xp-4,yp-4,racesmall[race][dir+(rand() % 3)*4], color );
                       else
                         putpiccolorize (xp-4,yp-4,racesmall[race][dir+get_step(&step)], color);
                    }

                  if (sabottimer > 3)
                    { putnpic (160-39,100-8,animspr[ANM_SABOTWINDOW][0]);
                      o = (160-39+6)+(100-8+10)*320;
                      x = 8;
                      for (y = 0; y < 4; y++)
                        { memmove ( (ruutu+o),(animspr[ANM_SABOTBAR][0]+x),(int)sabottimer);
                          o += 320;
                          x += 65;
                        }
                    }


                  if (citymsgtime)
                    if (citymsg[0]) writemid (160,90,citymsg);
               }

/*               allworketc */
//             allworklen = 0; allworklines = 0; showallwork = 1;
             if (showallwork)
               {
                  y = 4;
                  if (allworklen < 50) allworklen++;
                  for (i = 0; i < allworklines; i++)
                    {  writef (19,y,allworketc,2);
                       y += 9;
                    }
                  if (allworklen)
                    {  strcpy (rivi,allworketc);
                       rivi[allworklen] = 0;
                       writef (19,y,rivi,2);
                    }

                  if (allworklen > 45)
                    {  if (y < 190)
                         {  allworklines++;
                            allworklen = 0;
                         }
                    }
               }
               
             flip(); changed = 0;
          }

        if (!counter)
          {  if (!wormphase)
               {  if ( (rand() % 150) == 5)
                    {  wormx = (rand()% (mapsize->maxx - mapsize->minx - 10))+ mapsize->minx + 5;
                       wormy = (rand()% (mapsize->maxy - mapsize->miny - 10))+ mapsize->miny + 5;
                       wormphase = 1;
                       wormcount = 3;
                    }
               }
             else
               {  if ((--wormcount) == 0)
                    {  wormcount = 3;
                       wormphase++;
                       if (wormphase == 19)
                         wormphase = 0;
                    }
               }

             if (!fishphase)
               {  if ( (rand() % 100) == 5)
                    {  i = 0;
                       do { o = (rand() % 81);
                            fishx = ( (o % 9)*22)+12+11-7;
                            fishy = ( (o / 9)*22)+1+11-7;
                            fishx += (rand() % 7);
                            fishy += (rand() % 7);
                            if ( (planetmap[1][o] < 13) || (planetmap[1][o] > 38) )
                              o = -1;
                            if ( mapsize->allowtable[o] == 0) o = -1;
                            i++;
                          } while ( (o == -1) || (i < 100) );
                       if (o != -1)
                         {  fishphase = 1;
                            fishcount = 3;
                         }
                    }
               }
             else
               {  if ((--fishcount) == 0)
                    {  fishcount = 3;
                       fishphase++;
                       if (fishphase == 8)
                         fishphase = 0;
                    }
               }
               
             walked = 0;
             if (citymsgtime)
               {  citymsgtime--;
                  if (!citymsgtime)
                    {  citymsg[0] = 0; }
               }

             movecounter--;

              // incity movement ------------------------------------
             if ( (incity) && (movecounter <= 0) )
               {  counter = 1;
                  movecounter = 1;
                  readjoy();

                  if (muletaken)
                    {  if (mfit)
                         {  if (yp < 80) { yp++; dir = 2; walked++; }

                            if (mfit == 2)
                              {  if (++mfittimer > 1)
                                   {  myp--; mfittimer = 0; }
                                 if (myp == 50) mfit = 3;
                              }
                            if (mfit == 3)
                              {  if (++mfittimer > 1)
                                   {  myp++; mfittimer = 0; }
                                 if (myp == 80) {  mfit = 0; mulefitted = mfitto; }
                              }

                            if (mfit == 1)
                              {  if (mxp < mtox) { mxp ++; mdir = 1; }
                                 if (mxp > mtox) { mxp --; mdir = 3; }
                                 if (mxp ==mtox) { mfit = 2; mdir = 2; }
                              }
                            mstep++;
                         }
                       else
                         {  xm = (mxp-xp)*(mxp-xp) + (myp-yp)*(myp-yp);
                            if (xm > 128)
                              {  if (myp < yp) { myp++; mdir = 0; }
                                 if (myp > yp) { myp--; mdir = 2; }
                                 if (mxp > xp) { mxp--; mdir = 3; }
                                 if (mxp < xp) { mxp++; mdir = 1; }
                                 mstep++;
                              }
                         }
                    }

                  if (canact)
                    {  if ( (getk(plr,K_UP)) && (yp > 57) && (!mfit) )
                         {  if ((yp <= 80) && (xhitable[xp])) yp --;
                            if (yp > 80) yp--;
                            dir = 0; walked++;
                         }
                       if ( (getk(plr,K_DOWN)) && (yp < 120) && (!mfit)  )
                         {  if ((yp >= 86) && (xlotable[xp])) yp ++;
                            if (yp < 86) yp++;
                            dir = 2; walked++;
                         }
                       if ((getk(plr,K_RIGHT)) && (!mfit) )
                         {  if ( (yp >= 80) && ( yp <= 86) ) xp ++;
                            if ( (yp < 80) && (xhitable[xp+1]) ) xp++;
                            if ( (yp > 86) && (xlotable[xp+1]) ) xp++;
                            if (xp >= 193)
                              { if ( (muletaken) && (!mulefitted) )
                                  {  if (!citymsgtime)
                                       {  strcpy (citymsg, "Must outfit mule first!");
                                          citymsgtime = 100;
                                          play_errorsound();
                                       }
                                     xp = 192;
                                  }
                                else
                                  {  incity = 0; mdir = 3; mxp = xp = 127;
                                     myp = yp = 100; changed |= 0x10;
                                  }
                              }
                            dir = 1; walked++;
                         }
                       if ((getk(plr,K_LEFT)) && (!mfit) )
                         {  if ( (yp >= 80) && ( yp <= 86) ) xp --;
                            if ( (yp < 80) && (xhitable[xp-1]) ) xp--;
                            if ( (yp > 86) && (xlotable[xp-1]) ) xp--;
                            dir = 3; walked++;
                            if (xp <= 3)
                              { if ( (muletaken) && (!mulefitted) )
                                  {  if (!citymsgtime)
                                       {  strcpy (citymsg, "Must outfit mule first!");
                                          citymsgtime = 100;
                                          play_errorsound();
                                       }
                                     xp = 4;
                                  }
                                else
                                  { incity = 0; mdir = 3; mxp = xp = 95; myp = yp = 100; changed |= 0x10;}
                              }
                         }
                    } // if canact

                  if ( (muletaken == 0) && (yp == 110) && (xp >= 139) && (xp <= 166) )
                    {  if (plr_money[plr] <= muleprice)
                         {  if (!citymsgtime)
                              {  strcpy (citymsg, "Not enough credits!");
                                 citymsgtime = 100;
                                 play_errorsound();
                              }
                         }
                       else
                         {  if ( (dir == 2) && (shop_mules > 0) )
                              {  muletaken = 2; mulefitted = 0; // MULE BOUGHT
                                 plr_money[plr] -= muleprice;
                                 mxp = xp; myp = yp; mdir = dir;
                                 mfit = 0;
                                 shop_mules--;
                                 strcpy (citymsg, "Mule taken");
                                 citymsgtime = 50;
                              }
                         }
                    }

                      /* sample:     0 - none
                                 12345 - sample taken (1=none, 5=veryhigh)
                                     6 - sample not taken yet
                                    -1 - told to get sample
                                    -2 - analyzed */

                  if ( (xp >=27) && (xp <= 39) && (yp < 95) ) // ASSAY
                    {  if (sampletaken == -1)
                         {  sampletaken = 6;
                         }
                       if (sampletaken == -2)
                         {  sampletaken = 0;
                         }
                    }
                  if ( (xp >=27) && (xp <= 39) && (yp > 99) ) // ASSAY
                    {
                       switch (sampletaken)
                         { case  0: strcpy (citymsg, "Get a sample of ground and return");
                                    citymsgtime = 100;
                                    sampletaken = -1;
                                    break;
                           case  1: strcpy (citymsg, "No cristite found in sample");
                                    citymsgtime = 100; sampletaken = -2;
                                    setknowncrist (samplefrom, 0);
                                    break;
                           case  2: strcpy (citymsg, "Low cristite found in sample");
                                    citymsgtime = 100; sampletaken = -2;
                                    setknowncrist (samplefrom, 1);
                                    break;
                           case  3: strcpy (citymsg, "Medium cristite found in sample");
                                    citymsgtime = 100; sampletaken = -2;
                                    setknowncrist (samplefrom, 2);
                                    break;
                           case  4: strcpy (citymsg, "High cristite found in sample");
                                    citymsgtime = 100; sampletaken = -2;
                                    setknowncrist (samplefrom, 3);
                                    break;
                           case  5: strcpy (citymsg, "Very high cristite found in sample");
                                    citymsgtime = 100; sampletaken = -2;
                                    setknowncrist (samplefrom, 4);
                                    break;
                           case 10: switch (beersample % 42)
                                      {  case 0 : strcpy (citymsg, "Beer quality is excellent"); break;
                                         case 1 : strcpy (citymsg, "Very high alcohol found in sample"); break;
                                         case 2 : strcpy (citymsg, "Whiskey. Judged excellent."); break;
                                         case 3 : strcpy (citymsg, "It's stale, don't drink it"); break;
                                         case 4 : strcpy (citymsg, "Beer is warm, get another sample"); break;
                                         case 5 : strcpy (citymsg, "It's watered down. Get refund."); break;
                                         case 6 : strcpy (citymsg, "It's apple juice, not cider"); break;
                                         case 7 : strcpy (citymsg, "We don't do drinks"); break;
                                         case 8 : strcpy (citymsg, "Your sample is stale"); break;
                                         case 9 : strcpy (citymsg, "No cristite found in sample"); break;
                                         case 10: strcpy (citymsg, "It's warm beer. Better than no beer, though"); break;
                                         case 11: strcpy (citymsg, "Beauty is in eye of the beer holder"); break;
                                         case 12: strcpy (citymsg, "You didn't bring any beer nuts?"); break;
                                         case 13: strcpy (citymsg, "Beer! Now that's a temporary solution!"); break;
                                         case 14: strcpy (citymsg, "In heaven there is no beer. Drink now."); break;
                                         case 15: strcpy (citymsg, "Nothing cures nerves like beer"); break;
                                         case 16: strcpy (citymsg, "Non-alcoholic?!? You're kidding!"); break;
                                         case 17: strcpy (citymsg, "24 hours in a day, 24 beers in a case..."); break;
                                         case 18: strcpy (citymsg, "They who drink beer will think beer"); break;
                                         case 19: strcpy (citymsg, "Great beer bellies are made, not born"); break;
                                         case 20: strcpy (citymsg, "Keep your beer cold"); break;
                                         case 21: strcpy (citymsg, "Always keep beer in cold, dark place"); break;
                                         case 22: strcpy (citymsg, "Help! I fell and can't reach beer!"); break;
                                         case 23: strcpy (citymsg, "Scotty! Beam me down another beer!"); break;
                                         case 24: strcpy (citymsg, "This is beerware. If it works, buy yourself a beer"); break;
                                         case 25: strcpy (citymsg, "A few samples short of a sixpack, still..."); break;
                                         case 26: strcpy (citymsg, "All this beer... And only one mouth"); break;
                                         case 27: strcpy (citymsg, "Budweiser is like sex in a canoe . . ."); break;
                                         case 28: strcpy (citymsg, "Beam me up Scotty, this planet has no beer!"); break;
                                         case 29: strcpy (citymsg, "Beertender! Bring me another bar! <hic>"); break;
                                         case 30: strcpy (citymsg, "Drink and drive resposibly. Don't spill the beer!"); break;
                                         case 31: strcpy (citymsg, "All should believe. I believe I have one more beer"); break;
                                         case 32: strcpy (citymsg, "Hebrew - the MANLY beer!"); break;
                                         case 33: strcpy (citymsg, "To beer or not to beer?"); break;
                                         case 34: strcpy (citymsg, "Math and alcohol don't mix. Don't drink and derive."); break;
                                         case 35: strcpy (citymsg, "Don't spill it, it's alcohol abuse!"); break;
                                         case 36: strcpy (citymsg, "Five years old Scotch. Excellent!"); break;
                                         case 37: strcpy (citymsg, "I don't do jogging, it makes my beer all foamy"); break;
                                         case 38: strcpy (citymsg, "Never take beer to a job interview"); break;
                                         case 39: strcpy (citymsg, "Non-alcoholic beer? Is that a joke or what?"); break;
                                         case 40: strcpy (citymsg, "Beer and women: Two of God's best gifts to mankind"); break;
                                         case 41: strcpy (citymsg, "Choking on a beernut? Apply the Heineken maneuver."); break;
                                         case 42: strcpy (citymsg, "Very high cristite found in sample"); break;
                                         
                                      }
                                    citymsgtime = 100; sampletaken = -2;
                                    break;
//                         case -1: ; // told to get sample
//                         case -2: ; // analyzed already
                         } // switch
                         
                    }

                  if ( (xp >=86) && (xp <= 93) && (yp > 95) ) // BAR
                    {  if (muletaken)
                         {  if (!citymsgtime)
                              {  strcpy (citymsg, "You can't take mule in bar!");
                                 citymsgtime = 100;
                                 play_errorsound();
                              }
                         }
                       else
                         if (sampletaken)
                           {  if ( (sampletaken == -1) || (sampletaken == 6) )
                                {  sampletaken = 10;
                                   strcpy (citymsg, "Sample acquired");
                                   citymsgtime = 100;
                                }
                           }
                         else
                           {  do { o = rand() % (40+(month*15));
                                   if (leader == plr)
                                     o -= (rand() % 80);
                                   o -= rand() % 40;
                                 } while (abs(o) < 10);

                              if (o < 0)
                                {  if ((plr_money[plr]+o) < 0)
                                     o = -plr_money[plr];
                                   sprintf (rivi,"You lost %i by gambling", -o);
                                   msgwindow (rivi,"","");
                                }
                              else
                                {  sprintf (rivi,"You won %i by gambling", o);
                                   msgwindow (rivi,"","");
                                }
                              nobartime[plr] = 0;  
                              delayp (plr, idelaytime);
                              plr_money[plr] += o;

                              break;
                           } // if sampletaken else
                    } // if xp>=86 ... BAR

                  if ( (muletaken) && (yp < 60) && (!mfit) )
                    {  if ( (xp >= 27) && (xp <= 36) ) { mfitto = R_CRYSTAL+1; ym = 100; mtox = 31; }
                       if ( (xp >= 71) && (xp <= 81) ) { mfitto = R_ENERGY+1; ym = 85; mtox = 76; }
                       if ( (xp >=117) && (xp <=126) ) { mfitto = R_FOOD+1; ym = 50; mtox = 121; }
                       if ( (xp >=162) && (xp <=172) ) { mfitto = R_ORE+1; ym = 75; mtox = 166; }

                       if (plr_money[plr] < ym)
                         {  if (!citymsgtime)
                              {  strcpy (citymsg, "Not enough credits!");
                                 citymsgtime = 100;
                                 play_errorsound();
                              }
                         }
                       else
                         {  if (mfitto != mulefitted)
                              {  if (!citymsgtime)
                                   {  strcpy (citymsg, "Outfitting mule...");
                                      citymsgtime = 100;
                                   }
                                 plr_money[plr] -= ym;

                                 playsound (SND_OUTFIT,22050);
                                 
                                 mfit = 1;
                              }
                         }

                       
                    }

                  if ( (muletaken == 2) && (yp == 90) )
                    muletaken = 1;

                  if ( (muletaken == 1) && (yp == 120) && (xp >= 139) && (xp <= 166) )
                    {  muletaken = 0;
                       plr_money[plr] += muleprice * 2 / 3;
                       strcpy (citymsg, "Mule sold");
                       citymsgtime = 100;
                       shop_mules++;
                    }

               } // if incity
      // ---------------------------------------------------------------
      // incity ends, wilderness starts
             else
               {  counter = 2;
                  if (movecounter <= 0)
                    {  readjoy();
                       x = (xp-12) / 22;
                       y = (yp-1) / 22;

                       minx = (xp-12) % 22;
                       miny = (yp-1) % 22;

                       mapspr = mapbacksprites[map1(x,y)];

                       b = *(mapspr+miny*22+minx+8);

                       switch (b)
                         {  case 1 : movecounter = 1; // normal land
                                     break;
                            case 2 : movecounter = 3; // mountains
                                     break;
                            case 3 : movecounter = 3; // water
                                     break;

                         }
               
                       if (mulerunaway)
                         {  if (mdir == 1) mxp += 2;
                            if (mdir == 3) mxp -= 2;
                            if (mxp < 17) mulerunaway = 0;
                            if (mxp > 205) mulerunaway = 0;
                            mstep++;
                         }
                       if (muletaken)
                         {  xm = (mxp-xp)*(mxp-xp) + (myp-yp)*(myp-yp);
                            if (xm > 64)
                              {  if (myp < yp) { myp++; mdir = 2; }
                                 if (myp > yp) { myp--; mdir = 0; }
                                 if (mxp > xp) { mxp--; mdir = 3; }
                                 if (mxp < xp) { mxp++; mdir = 1; }
                                 mstep++;
                              }
                         }

                       if (canact)
                         {  if ( (getk(plr,K_FIRE)) && (wormphase) )
                              {  if ( (abs(xp-(wormx+7)) < 7) && (abs(yp-(wormy+5)) < 7) )
                                   {  setk (plr,K_FIRE,0);
                                      plr_money[(int)plr] += 200;
                                      strcpy (citymsg, "You have captured a Purple Worm!");
                                      if (muletaken)
                                        {  mulerunaway = 1; muletaken = 0;
                                           if (xp < 120) mdir = 3; else mdir = 1;
                                        }
                                      citymsgtime = 100;
                                      wormphase = 0;
                                   }
                              }
                            if ( (getk(plr,K_FIRE)) && (sampletaken) )
                              {  setk (plr,K_FIRE,0);
                                 if (sampletaken == 6) // take sample...!
                                   {  samplefrom = ((xp-12) / 22) + ((yp-1) /22)*9;
                                      sampletaken = (planetres[R_CRYSTAL][samplefrom] / 10)+1;
                                      strcpy (citymsg, "Sample taken, return to assay");
                                      citymsgtime = 100;
                                   }
                              }
     
                            if (getk(plr,K_DOWN))
                              {  if (yp < mapsize->maxy) yp++; dir = 2; walked++;
                              }

                            if (getk(plr,K_UP))
                              {  if (yp > mapsize->miny) yp--; dir = 0; walked++;
                              }
               
                            if (getk(plr,K_RIGHT))
                              {  if (xp < mapsize->maxx) xp++; dir = 1; walked++;
                              }
               
                            if (getk(plr,K_LEFT))
                              {  if (xp > mapsize->minx) xp--; dir = 3; walked++;
                              }
     
                            if (getk(plr,K_FIRE))
                              {  if (muletaken)
                                   {  setk (plr,K_FIRE,0);
                                      o = ((xp-12) / 22) + (((yp-1) / 22) * 9);
                                      xm = (xp-12) % 22;
                                      ym = (yp-1) % 22;
                                      if ( (xm > 10) && (ym < 12) && (mapowner[o]-1 == plr) )
                                        {  xm = mapprod[o]; // exchange mules
                                           muletaken = 0;
                                           mapprod[o] = mulefitted;
                                           changed |= 0x10;
               
                                           if (xm) // exchange; take other with
                                             {  mulefitted = xm;
                                                muletaken = 1;
                                             }
                                        }
                                      else
                                        {  mulerunaway = 1; muletaken = 0;
                                           if (xp < 120) mdir = 3; else mdir = 1;
                                        }
                                   }
                                 else
                                   {  // square
                                      o = ((xp-12) / 22) + (((yp-1) / 22) * 9);
                                      // exact place in square
                                      xm = (xp-12) % 22;
                                      ym = (yp-1) % 22;
               
                                      if ( (xm > 10) && (ym < 12) && (mapowner[o]-1 == plr) && (mapprod[o]) )
                                        {  muletaken = 1;
                                           mulefitted = mapprod[o];
                                           mapprod[o] = 0;
                                           changed |= 0x10;
                                           mxp = xp;
                                           myp = yp;
                                           mdir = dir;
                                           setk (plr,K_FIRE,0);
                                        }


                                      cutthroat = 1;
                                      // cutthroat ; sabotage
                                      if ( (xm > 10) && (ym < 12) && (mapowner[o]-1 != plr) && (mapprod[o]) && (cutthroat) )
                                        {  sabottimer += 0.45;
                                           setk (plr,K_FIRE,0);
                                           if (sabottimer >= 65)
                                             { y = (rand() % 10);
                                               switch (y)
                                                 { case 0 : strcpy (citymsg, "You managed to steal the mule!");
                                                            citymsgtime = 100;
                                                            muletaken = 1; mulefitted = mapprod[o]; mapprod[o] = 0;
                                                            break;
                                                            
                                                   case 1 : strcpy (citymsg, "You destroyed the mule!");
                                                            citymsgtime = 100;

                                                            mapprod[o] = 0;
                                                            break;

                                                   case 2 : strcpy (citymsg, "Oops...");
                                                            citymsgtime = 100;
                                                            break;

                                                   default: strcpy (citymsg, "Your attempt failed");
                                                            citymsgtime = 100;
                                                            break;
                                                 }
                                               sabottimer = 0;
                                               changed |= 0x10;  
                                             }
                                        }
                                      else
                                        sabottimer = 0;
                                   }
                              }
                            else
                              sabottimer = 0;

                            if (getk(plr,K_FIRE)) // nothing else, so check others ...
                              {  x = (xp-12) / 22; y = (yp-1) / 22;
                                 if ( (map1(x,y) >= 13) && (map1(x,y) <= 38) )
                                   {  b = 1; fishtries++;
                                      if ( (fishtries > 5) && ( (rand() % 20) == 5) && (citymsgtime == 0) )
                                        {  strcpy (citymsg, "Maybe you should try Procyon lures?");
                                           citymsgtime = 100; b = 0;
                                        }

                                      if (fishtries < 5)
                                        b = 0;

                                      if ( (b) && (citymsgtime == 0) )
                                        {  switch (beersample % 32)
                                             {  case 0 : strcpy (citymsg, "<splash!> <splash!>"); break;
                                                case 1 : strcpy (citymsg, "<swoosh!> <squirt!>"); break;
                                                case 2 : strcpy (citymsg, "You get no fish"); break;
                                                case 3 : strcpy (citymsg, "Bad luck, not a bite"); break;
                                                case 4 : strcpy (citymsg, "Don't you have work to do?"); break;
                                                case 5 : strcpy (citymsg, "You have no time to fish!"); break;
                                                case 6 : strcpy (citymsg, "Damn slippery things are too quick!"); break;
                                                case 7 : strcpy (citymsg, "You get yourself all wet"); break;
                                                case 8 : strcpy (citymsg, "You fall in water almost drowning yourself"); break;
                                                case 9 : strcpy (citymsg, "It's a pretty day to fish..."); break;
                                                case 10: strcpy (citymsg, "You admire your reflection for a while"); break;
                                                case 11: strcpy (citymsg, "A fish jumps, splashing water all over you"); break;
                                                case 12: strcpy (citymsg, "You thought you saw Elvis down there..."); break;
                                                case 13: strcpy (citymsg, "It's water, all right"); break;
                                                case 14: strcpy (citymsg, "It's wet, all right"); break;
                                                case 15: strcpy (citymsg, "Tastes pretty good"); break;
                                                case 16: strcpy (citymsg, "What about all that bacteria?"); break;
                                                case 17: strcpy (citymsg, "Well, you ARE thirsty..."); break;
                                                case 18: strcpy (citymsg, "Blood is thicker than water, and tastier"); break;
                                                case 19: strcpy (citymsg, "Conserve water. Drink beer."); break;
                                                case 20: strcpy (citymsg, "Do artificial plants need artificial water?"); break;
                                                case 21: strcpy (citymsg, "Does water sink or float...?"); break;
                                                case 22: strcpy (citymsg, "Well, it definitely is NOT dehydrated water!"); break;
                                                case 23: strcpy (citymsg, "Looks pretty deep..."); break;
                                                case 24: strcpy (citymsg, "You can't swim!"); break;
                                                case 25: strcpy (citymsg, "Watch it, drinking that might kill your thirst!"); break;
                                                case 26: strcpy (citymsg, "Don't drink it, fish breed in it!"); break;
                                                case 27: strcpy (citymsg, "Wish you had taken your surfboard..."); break;
                                                case 28: strcpy (citymsg, "<sniff> When you took your last bath, anyway?"); break;
                                                case 29: strcpy (citymsg, "You wet your rod, with no success"); break;
                                                case 30: strcpy (citymsg, "<ouch!> You were bit by a fish!"); break;
                                                case 31: strcpy (citymsg, "Fish ate with an eye. Yuck."); break;
                                             }
                                           citymsgtime = 100; b = 0;
                                        }
                                     setk (plr, K_FIRE, 0);
                                   } // if river
                              } // k_fire
          
                            if ((xp > 99) && (xp < 120) && (yp > 86) && (yp < 111))
                              {  incity = 1;
                                 mxp = xp = 20+(xp-100)*8;
                                 myp = yp = 83;
                                 changed |= 0x10;
                                 dir = 2;
                              }
                        } // if canact
                    } // IF MOVECOUNTER<=0
               } // if incity ELSE
               
             changed |= 1;
             if (walked) step++;
          } // if !counter

        check_shutdown();
     }

   timetick_speed = -1; // INACTIVE!

   timer_routine = NULL;

}

void initialize_game()
{  int i;
   for (i = 0; i < 4; i++)
     {  plr_money[i] = 1200;
        plr_energy[i] = 3;
        plr_food[i] = 6;
        plr_ore[i] = 0;
        plr_crystal[i] = 0;
        posit[i] = i;
        comp_reaction[i] = 2; // computers have average reaction time
        comp_strategy[i] = rand() % 2;
        comp_pricelevel[i] = ((float)(rand() % 5)) / 10;
        nobartime[i] = 0;

        if (demogame) plrcontrol[i] = 0;
     }
   leader = 99; // no leader yet
   exitgame = 0;

   priceangle = ((float)(rand() % 60)) / 10;

   month = 0;
   shop_food = 10;
   shop_energy = 10;
   shop_ore = 10;
   shop_crist = 40;

   shop_oreprice = 60;
   shop_foodprice = 40;
   shop_energyprice = 35;
   shop_crystalprice = 80;

   shop_mules = 10;

   landauct_startprice = 200;
   landauct_startprice += (rand() % 10)*20;


}


void score_month()
{  int c,i,y;

   if (exitgame) return;

   for (i = 0; i < 4; i++)
     {  goodsscore[i] = landscore[i] = scores[i] = 0;
        posit[i] = i;
     }
   purakuva ("stats.dat", ruutu); setpale (64,64,64);

   sprintf (rivi,"STATISTICS IN END OF MONTH %i", month);
   writemid (160,7,rivi);

   for (i = 0; i < 4; i++)
     {  scores[i] += plr_money[i];
        goodsscore[i] += shop_oreprice * plr_ore[i];
        goodsscore[i] += shop_foodprice * plr_food[i];
        goodsscore[i] += shop_energyprice * plr_energy[i];
        goodsscore[i] += shop_crystalprice * plr_crystal[i];
        scores[i] += goodsscore[i];

        for (c = 0; c < 81; c++)
          if (mapowner[c] == i+1)
            landscore[i] += 300+get_neighborcount(c,i+1)*10;
        scores[i] += landscore[i];
     }


   while(1)
     {  c = 0;
        for (i = 1; i < 4; i++)
          if (scores[posit[i]] > scores[posit[i-1]])
            {  c++;
               iswap (&posit[i], &posit[i-1]);
            }
        if (c == 0) break;
        if (keybuffer[1]) break;
     }

   for (i = 0; i < 4; i++)
     {  c = posit[i];
        y = 30+i*40;
        putpiccolorize (80,y+5, racesprites[plrrace[c]][2],colortable2[c+1] );

        writef (130,y,"Credits:",2);
        writef (130,y+7,"Goods:",2);
        writef (130,y+14,"Land:",2);
        writef (130,y+21,"TOTAL:",1);

        itoa (plr_money[c],rivi,10); writef (200,y,rivi,2);
        itoa (goodsscore[c],rivi,10); writef (200,y+7,rivi,2);
        itoa (landscore[c],rivi,10); writef (200,y+14,rivi,2);
        itoa (scores[c],rivi,10); writef (200,y+21,rivi,1);
     }
   leader = posit[0];

   flip();

   reset_keys();
   delayi (idelaytime);

   if ( (demogame) && (month == game_length) )
     {  i = 50;
        while (i--)
          {  delay (1);
             if ( (keybuffer[28]) || (keybuffer[1]) ) break;
          }
     }
#ifdef DEBUG
   if (month == game_length)
     { while (keybuffer[1]) ;
       while (!keybuffer[1]) ;
     }
#endif

}

void load (int month)
{  FILE *tied;
   itoa (month, rivi, 10);
   strcat (rivi,".sav");
   tied = fopen (rivi, "rb");
   fread ((void*)&month,1779,1, tied);
   fclose (tied);
}

void main_gameloop()
{  int i,c, *o;
   FILE *tied;

//   load (4);

   ingame = 1;
   if (demogame)
     idelaytime = 25;
   else
     idelaytime = IDELAYTIME;

   while ( (month < game_length) && (!exitgame) )
     {  //-------savegame
/*        itoa (month+1, rivi, 10);
        strcat (rivi,".sav");
        tied = fopen (rivi, "wb");
        fwrite ((void*)&month,(long) ( (void*)&savegame_end-(void*)&savegame_beg ),1, tied);
        fclose (tied); */
        //-----------save-end


        init_month(); // random event

        land_grand();

        c = 3;
        while ( ( (rand() % c) == 0) && (c < 8) )
          {  land_auction(); c += 2;  }

        for (i = 0; i < 4; i++)
          if (plrcontrol[posit[i]])
            {  player_activities(posit[i]);
            }
          else
            {  computer_activities(posit[i]);
            }
        timetick_speed = -1; // deactivate once more... just in case

        random_event();
        check_shopprices();

        show_productions();
        afterturn_random_event();

        goods_auction();

        score_month();
     }

   timetick_speed = -1;
   landgrand_accelerate = 0;

   ingame = 0;
}

//17,7
void colorize (int xp,int yp, int clr)
{  int x,y;
   for (x = 0; x < 17; x++)
     for (y = 0; y < 7; y++)
       *((char*)(ruutu)+(xp+x)+(yp+y)*320) = (*((char*)(ruutu)+(xp+x)+(yp+y)*320) & 0x0f) + clr;
}


void color_select()
{  int clr,clrseld[8],i,z;

   memset (ruutu,64000,0); flip();
   
   purakuva ("clrselb.dat", ruutu); setpale (64,64,64);
   timer_routine = landgrand_timerrout;

   writemid (160,35,"SELECT PLAYER COLORS");

   writemid (160,150,"To select your color, press fire when the color");
   writemid (160,160,"is shown in square in middle of the screen");

   for (i = 0; i < 5; i++)
     colortable[i] = 0;

   landgrand_accelerate = 0;

   clr = 0;

   for (i = 1; i < 7; i++) clrseld[i] = 0;
   counter = 0;
   
   while (1)
     {  if (!counter)
          {  do { clr++;
                  if (clr > 6) clr = 1;
                } while (clrseld[clr]);
             set_gridpal (clr);
             counter = 50;
             flip();
          }

        readjoy();
        for (i = 0; i < 4; i++)
          if ( (plrcontrol[i]) && (!colortable[i+1]) && (getk(i,K_FIRE)) )
            {  colortable[i+1] = clr;
               colortable2[i+1] = colortableouter[colortable[i+1]];
               colorize (120+21*i,140, colortable2[i+1]);
               clrseld[clr] = 1;
               counter = 0;
               setk (i,K_FIRE,0);
            }

        z = 0;
        for (i = 0; i < 4; i++)
          {  if (!plrcontrol[i])
               z++;
             else
               if (colortable[i+1]) z++;
          }
        if (z==4) break;

        check_shutdown();
     }

   for (i = 0; i < 4; i++)
     if (!plrcontrol[i])
       while (1)
         {  z = (rand() % 6) +1;
            if (!clrseld[z])
              {  colortable[i+1] = z;
                 colortable2[i+1] = colortableouter[colortable[i+1]];
                 colorize (120+21*i,140, colortable2[i+1]);
                 clrseld[z] = 1;
                 flip();
                 break;
              }
         }

   delayap (50);

   for (i = 0; i < 5; i++)
     colortable2[i] = colortableouter[colortable[i]];
}

void racesel_putsprites(int i)
{  putpiccolorize (119,44, racesprites[1][6], colortable2[i+1]); // 1
   putpiccolorize (148,44, racesprites[2][6], colortable2[i+1]); // 2
   putpiccolorize (177,44, racesprites[3][6], colortable2[i+1]); // 3

   putpiccolorize (177,73, racesprites[4][6], colortable2[i+1]); // 4

   putpiccolorize (177,102,racesprites[5][6], colortable2[i+1]); // 5
   putpiccolorize (148,102,racesprites[6][6], colortable2[i+1]); // 6
   putpiccolorize (119,102,racesprites[7][6], colortable2[i+1]); // 7

   putpiccolorize (119,73, racesprites[8][6], colortable2[i+1]); // 8
}

char racename[9][27] =
    { "",
      "HUMANOID - EXPERT SPECIES",
      "MECHANOID",
      "BIRDMEN - BEGINNER SPECIES",
      "?",
      "?",
      "PACMEN",
      "WORMS",
      "POWERMEN" };

char raceinfo1[9][3][70] =
    { {"","",""},

      {"Humanoids are usually short on cash and time,",
       "which makes them real experts' species",
       ""},
      
      {"Mechanoids are fast and powerful, but not too",
       "bright. Computer likes to play with this race.",
       ""},

      {"Birdmen have lots of extra cash and time",
       "making them idea for beginner players.",
       ""},

      {"?",
       "",
       ""},
        
      {"?",
       "",
       ""},
      
      {"No matter what you do, they just can't be",
       "held away from the bar!",
       ""},

      {"Worms like straight formations, but make terrible",
       "shepherds for they have a habit of grabbing nearest",
       "sheep and tossing it at nearest other worm on sight..."},

      {"Weird energy-based lifeform no one wants to go near of.",
       "They can do magic with everything that has something",
       "to do with energy, but are fairly bad with other things."} };


char racesel_left[9]  = { 8, 1, 1, 2, 0, 6, 7, 7, 8 };
char racesel_right[9] = { 4, 2, 3, 3, 4, 5, 5, 6, 0 };
char racesel_up[9]    = { 2, 1, 2, 3, 3, 4, 0, 8, 1 };
char racesel_down[9]  = { 6, 8, 0, 4, 5, 5, 6, 7, 7 };

void race_selects()
{  int i,sel,lsel;

   int selx[9] = { 145, 116,145,174,174,174,145,116,116 };
   int sely[9] = {  70, 41,41,41,70,99,99,99,70 };

   memset (ruutu,0,64000); flip();

   purakuva ("racesels.dat", ruutu);
   spritedest = ruutu;
   getpic (0,0,30,30, ruutu2);

   purakuva ("racesel.dat", ruutu); setpale (64,64,64);
     // draw sprites: clockwise direction

   writemid (160,5,"SELECT RACE");
   writemid (160,20,"Press and hold down directional keys to select,");
   writemid (160,30,"then press fire.");

   memmove (backg,ruutu,64000);

   flip();

   for (i = 0; i < 4; i++)
     {  racesel_putsprites(i);
        set_gridpal (colortable[i+1]);
          // computer picking race
        if (!plrcontrol[i])
          {  plrrace[i] = 2; // computer alien.. heehee
             memmove (ruutu,backg,64000);
             racesel_putsprites(i);
             putnpic (selx[0],sely[0], ruutu2);
             flip();
             delayap (20);
             memmove (ruutu,backg,64000);
             racesel_putsprites(i);
             putnpic (selx[2],sely[2], ruutu2);
             flip();
             delayap (30);
          }
        else
          {  sel = 0; // player picking race
             counter = 0; lsel = -1;
             while (1)
               {  readjoy();
                  if ((getk(i,K_FIRE)) && (sel > 0) )
                    {  plrrace[i] = sel;
                       setk (i,K_FIRE,0);
                       break;
                    }
//                  sel = 0;
                  if (!counter)
                    {  if (getk(i,K_UP))
                         { setk (i,K_UP,0); sel = racesel_up[sel]; }
                         
                       if (getk(i,K_LEFT))
                         { setk (i,K_LEFT,0); sel = racesel_left[sel]; }
                         
                       if (getk(i,K_RIGHT))
                         { setk (i,K_RIGHT,0); sel = racesel_right[sel]; }
                         
                       if (getk(i,K_DOWN))
                         { setk (i,K_DOWN,0); sel = racesel_down[sel]; }
                    }
                  check_shutdown();

                  if (sel != 0)
                    { writemid (160,140,racename[sel]);

                      writemids(160,150,raceinfo1[sel][0]);
                      writemids(160,158,raceinfo1[sel][1]);
                      writemids(160,166,raceinfo1[sel][2]);
                    }

                  if (lsel != sel)
                    {  memmove (ruutu,backg,64000);
                       racesel_putsprites(i);
                       putnpic (selx[sel],sely[sel], ruutu2);
                       lsel = sel;
                    }

                  flip();
               }
          }
     }

   delayap (50);
}

void get_controlmethods()
{  int i,c,ctrlseld[20],seld;
   purakuva ("ctrlsel.dat", ruutu); setpale (64,64,64);
   memmove (backg, ruutu, 64000);
   flip();
   for (i = 0; i < 20; i++)
     {  ctrlseld[i] = 0;
        setkabs (i, K_FIRE, 0);
     }
     
   
   for (i = 0; i < 4; i++)
     if (i < players)
       {  memmove (ruutu, backg, 64000);
          sprintf (rivi, "Player #%i:", i+1);
          writemid (160,80,rivi);
          writemid (160,100,"Select your control method by pressing");
          writemid (160,110,"your fire key now.");

          flip();

          while (1)
            {  seld = 0;
               readjoy();
               for (c = 0; c < 5; c++)
                 if ( (getkabs(c,K_FIRE)) && (!ctrlseld[c]) )
                   {  setkabs (c, K_FIRE, 0);
                      ctrlseld[c] = 1;
                      plrcontrol[i] = c;
                      seld++;
                   }
               check_shutdown();
               if (seld) break;
            }
       }
     else
       {  plrcontrol[i] = 0;
       }
}

void start_new_game_func()
{
   get_controlmethods();

   create_map();

   initialize_game();
   color_select();
   race_selects();
   main_gameloop();
}


/*

this code is obsolete; it was used with command line
arguments and sound detection.


int detect(short *sndio, short *snddma, short *sndhighdma, short *sndirq)
{  char *env;
   char b,i,n,c;

   env = getenv ("BLASTER");
   if (env == NULL)
     return -1;
   *sndio = *sndhighdma = *snddma = *sndirq = 0; // 220
   i = 0;
   while ( (b = *(env+i++)) != 0 )
     {  if (b == 'A')
           { *sndio = ( *(env+i+1) - 0x30 ) << 4;
             *sndio += 0x200;
           } // if b=A
        if (b == 'D')
           { switch (*(env+i++))
                { case '0': { *snddma = 0; break; }
                  case '1': { *snddma = 1; break; }
                  case '3': { *snddma = 3; break; }
                }
           } //if b=D
        if (b == 'H')
           { switch (*(env+i++))
               { case '5': { *sndhighdma = 5; break; }
                 case '6': { *sndhighdma = 6; break; }
                 case '7': { *sndhighdma = 7; break; }
               }
           } //if b=H
        if (b == 'I')
           { switch (*(env+i++))
               { case '2': { *sndirq = 2; break; }
                 case '5': { *sndirq = 5; break; }
                 case '7': { *sndirq = 7; break; }
                 case '9': { *sndirq = 9; break; }
                 case '1': { switch (*(env+i++))
                              { case '0' : { *sndirq = 10; break; }
                                case '1' : { *sndirq = 11; break; }
                              }
                              break;
                           }
               }
           } //if b=D
     }
}

void check_sndargs(int argc, char *args[])
{  int i;
   char rivi[50];
   FILE *tied;
   char interp,dis16;
   short sndio,snddma,sndhighdma,sndirq;

   int usedev;

   usedev = 3;
   interp = 1;
   dis16 = 0;
   detect(&sndio, &snddma, &sndhighdma, &sndirq);

   tied = fopen ("sound.cfg", "rb");
   if (tied)
     {  fread ( &usedev, 4,1, tied);
        fread ( &interp, 1,1, tied);

        fread ( &unsigned16bit, 1,1, tied);

        fread ( &sndio, 2,1, tied);
        fread ( &snddma, 2,1, tied);
        fread ( &sndhighdma, 2,1, tied);
        fread ( &sndirq, 2,1, tied);

        fread ( &dis16, 1,1, tied);
        
        fclose (tied);
     }
   
   for (i = 1; i < argc; i++)
     {  strcpy (rivi, args[i]+1);
        strupr (rivi);
        if (!strncmp (rivi,"HELP",4))
          {  printf ("MULE Command line arguments:\n");
             printf ("  -HELP      - display this message\n");
             printf ("  -MONO      - use mono [no interpolation available]\n");
             printf ("  -STEREO    - use stereo\n");
             printf ("  -INTER     - use interpolation [affects stereo only]\n");
             printf ("  -NOINTER   - do not use interpolation [affects stereo only]\n");
             printf ("  -AUTO      - autodetect soundblaster, presuming stereo with interpolation\n");
             printf ("  -8BIT      - force 8bit audio output in case of audio troubles\n");
             printf ("  -16BIT     - enable 16bit audio output if available\n");
             printf ("  -NOSOUND   - disables all sounds\n");
             printf ("  -LIVE      - force usage of SoundBlaster LIVE! 16 bit mixing\n");
             printf ("    -IO:2x0  - specify SoundBlaster base address, in hex\n");
             printf ("    -DMA:x   - specify SoundBlaster 8bit DMA\n");
             printf ("    -HDMA:x  - specify SoundBlaster 16bit DMA\n");
             printf ("    -IRQ:xx  - specify SoundBlaster IRQ\n");
             printf ("All settings are stored and used until others are specified.\n");
             printf ("CONSULT YOUR SOUND HARDWARE MANUAL BEFORE CHANGING ANY CONFIGURATIONS WITH\n");
             printf ("IO, DMA, HDMA or IRQ SWITCHES, FOR YOU MIGHT CAUSE FATAL DAMAGE BY USING\n");
             printf ("SWITCHES INCORRECTLY. IMAGINATION CLAIMS NO RESPONSIBILITY FOR SUCH DAMAGE.\n");
             printf ("Current sound configuration:\n");
             if (usedev && sndio)
               {  printf ("  Sound Blaster: IO=%3x  IRQ=%i  DMA=%i  HDMA=%i\n",sndio,sndirq,snddma,sndhighdma);
                  if (dis16)
                    printf ("  16-bit mixing disabled\n");
                  else
                    printf ("  Using 16-bit mixing (if supported by sound hardware)\n");
                  if (usedev == 2)
                    printf ("  Mono mixer, no interpolation\n");
                  else
                    {  printf ("  Stereo mixer, ");
                       if (interp)
                         printf ("interpolation enabled.\n");
                       else
                         printf ("interpolation disabled.\n");
                    }
               }
             else
               {  printf ("No sound device found or in use.\n\n");
               }
             exit(0);
          }

        if (!strncmp (rivi,"8BIT",4)) dis16 = 1;
        if (!strncmp (rivi,"16BIT",5)) dis16 = 0;
        if (!strncmp (rivi,"MONO",4)) usedev = 2;
        if (!strncmp (rivi,"STEREO",6)) usedev = 3;
        if (!strncmp (rivi,"AUTO",4))
          {  detect(&sndio, &snddma, &sndhighdma, &sndirq); usedev = 3; interp = 1; }
        if (!strncmp (rivi,"INTER",5)) {  interp = 1; }
        if (!strncmp (rivi,"NOINTER",7)) {  interp = 0; }
        if (!strncmp (rivi,"NOSOUND",7)) {  usedev = 0; }
        if (!strncmp (rivi,"IO:2",4)) sndio = 0x220 + ( (rivi[4]-0x30) << 4);
        if (!strncmp (rivi,"DMA:",4)) snddma = rivi[4]-0x30;
        if (!strncmp (rivi,"HDMA:",5)) sndhighdma = rivi[4]-0x30;
        if (!strncmp (rivi,"LIVE",4)) { dis16 = 0; unsigned16bit = 1; }
        if (!strncmp (rivi,"IRQ:",4))
          {  if (rivi[4] == '1')
               {  if (rivi[5] == '0') sndirq = 10;
                  if (rivi[5] == '1') sndirq = 11;
               }
             else
               {  sndirq = rivi[4]-0x30;
               }
          }
     }

   tied = fopen ("sound.cfg", "wb");
   if (tied)
     {  fwrite ( &usedev, 4,1, tied);
        fwrite ( &interp, 1,1, tied);

        fwrite ( &unsigned16bit, 1,1, tied);

        fwrite ( &sndio, 2,1, tied);
        fwrite ( &snddma, 2,1, tied);
        fwrite ( &sndhighdma, 2,1, tied);
        fwrite ( &sndirq, 2,1, tied);

        fwrite ( &dis16, 1,1, tied);
        
        fclose (tied);
     }

   use_interpolation = interp;
   disable_16bitmix = dis16;
   if (sndio != 0)
     init_mixer(usedev, sndio, sndirq, snddma, sndhighdma, 20 );
}

*/

void show_withdrawal_warning()
{  int i;
   memset (ruutu, 0, 64000);
   writemid (160, 90,"WARNING!");
   writemid (160,100,"This can cause severe withdrawal symptoms!");
   writemid (160,115,"Press ESC to quit or any other key to proceed.");
   flip();
   for (i = 0; i < 128; i++)
     keybuffer[i] = 0;

   while(1)
     { for (i = 0; i < 128; i++)
         if (keybuffer[i]) break;
     }
}


int i; // debugcode

int main (int argc, char *args[])
{
   open_package ("gameg.pkg");

   debuglog ("--------------------------------------------------");
   debuglog ("Game Started");

     // allocate memory for sprites
   stockbar = (char*) malloc (16*2+16); // +64
   buyline = (char*) malloc (160*3+16); // +512 = 576
   sellline = (char*) malloc (160*3+16); // +512 = 1088
   stockpic1 = (char*) malloc (23*23+16); // +1024 = 2122
   stockpic2 = (char*) malloc (23*23+16); // +1024 = 3146
   shoppic = (char*) malloc (35*25+16); // +1024 = 4170
   city = (char*) malloc (64000); // 69706
   mapbackg = (char*) malloc (64000); // 135242
   shopmulepic = (char*) malloc (256); // 135498


//   disable_16bitmix = 1;

/*   check_sndargs(argc, args); */

    /* allocate temporary buffers */
   ruutu = malloc (64000); // 332106 // backbuffer
   ruutu2 = malloc (64000); // triple/temp buffer
   backg = malloc (64000); // background
   spritedest = ruutu;
   set320(); // setup video mode

     /* default keys... */
   plrkeys[1][K_FIRE] = 28;
   plrkeys[1][K_UP] = 72;
   plrkeys[1][K_DOWN] = 80;
   plrkeys[1][K_LEFT] = 75;
   plrkeys[1][K_RIGHT] = 77;

   plrkeys[2][K_FIRE] = 15;
   plrkeys[2][K_UP] = 17;
   plrkeys[2][K_DOWN] = 31;
   plrkeys[2][K_LEFT] = 30;
   plrkeys[2][K_RIGHT] = 32;

     /* debugcode ---> */
   plrcontrol[0] = 1; // plr 0: human, keys #1
   plrrace[0] = 1;
   plrcontrol[1] = 2; // plr 1: human, keys #2
   plrrace[1] = 1;
   plrcontrol[2] = 0; // plr 2: computer
   plrrace[2] = 1;
   plrcontrol[3] = 0; // plr 3: computer
   plrrace[3] = 1;
   restarts = 0;

     /* debug code */
/*   for (i = 0; i < 4; i++)
     { plr_money[i] = 2000;
     } */

   modvolume = 48;
   sfxvolume = 64;
   
   timetick_speed = -1; // no ticking... yet; could crash the game
   init_timers();
   timer_routine = NULL;
   set_pit (50);

   xclipmax = 319;
   yclipmax = 199;

     // load data
   load_font ("med.f", 1, 16384); // 332106 + x = 364874
   load_font ("tiny.f", 2, 16384);
   load_mapsprites();
   load_mapspeedsprites();
   load_selsprites();
   load_racesprites();
   load_smallracesprites();
   load_prodsprites();
   load_animsprites();

     // initial data
   colortable[1] = 1;
   colortable[2] = 2;
   colortable[3] = 3;
   colortable[4] = 4;
   colortable[5] = 0;

   initkeys();

     // sounds
   load_sound_configuration();
   load_sounds();

     // function pointers
   update_function = update_mapdecors;
   start_new_game = start_new_game_func;

   mod_load ("battlest.s3m");
   mod_start();
   mod_jumptotrack (44);

     // debug
   mule_intro();
   mule_mainmenu();

//   goods_auction();

//   joycheck();

     // minor eastern egg...
   if ( ((rand() % 500) == 50) && (restarts > 50) )
     show_withdrawal_warning();

   mod_release();

   disablekeys();

   textmode(3);

   store_config(); // sound and controls

   close_sound();
   close_timers();

   debuglog ("Normal exit...");

   printf ("MULE version %s\n", GAME_VERSION_STR);
   printf ("MULE is currently OPEN SOURCE;\n");
   printf ("please read MULE.DOC and OPENSRC.DOC for some explanations.\n");

}
